diff --git a/FSharpBuild.Directory.Build.props b/FSharpBuild.Directory.Build.props index a1ba7ab156d..515de9bbdc7 100644 --- a/FSharpBuild.Directory.Build.props +++ b/FSharpBuild.Directory.Build.props @@ -11,8 +11,7 @@ $(RepoRoot)src $(ArtifactsDir)\SymStore - $(ArtifactsDir)\Bootstrap - $(ArtifactsDir)/fsc/Proto/netcoreapp2.1 + $(ArtifactsDir)\Bootstrap 4.4.0 1182;0025;$(WarningsAsErrors) @@ -96,10 +95,10 @@ - $(ProtoOutputPath)\Microsoft.FSharp.Targets - $(ProtoOutputPath)\Microsoft.FSharp.NetSdk.props - $(ProtoOutputPath)\Microsoft.FSharp.NetSdk.targets - $(ProtoOutputPath)\Microsoft.FSharp.Overrides.NetSdk.targets + $(ProtoOutputPath)\fsc\Microsoft.FSharp.Targets + $(ProtoOutputPath)\fsc\Microsoft.FSharp.NetSdk.props + $(ProtoOutputPath)\fsc\Microsoft.FSharp.NetSdk.targets + $(ProtoOutputPath)\fsc\Microsoft.FSharp.Overrides.NetSdk.targets diff --git a/FSharpTests.Directory.Build.props b/FSharpTests.Directory.Build.props index 7c00805dda5..8a7a832a43e 100644 --- a/FSharpTests.Directory.Build.props +++ b/FSharpTests.Directory.Build.props @@ -32,9 +32,9 @@ - <_FSharpBuildTargetFramework Condition="'$(FSharpTestCompilerVersion)' == 'net40'">net472 - <_FSharpBuildTargetFramework Condition="'$(FSharpTestCompilerVersion)' == 'coreclr'">netcoreapp2.1 - <_FSharpBuildBinPath>$(MSBuildThisFileDirectory)artifacts\bin\FSharp.Build\$(Configuration)\$(_FSharpBuildTargetFramework) + <_FSharpBuildTargetFramework Condition="'$(MSBuildRuntimeType)'!='Core'">net472 + <_FSharpBuildTargetFramework Condition="'$(MSBuildRuntimeType)'=='Core'">netcoreapp2.1 + <_FSharpBuildBinPath>$(MSBuildThisFileDirectory)artifacts\bin\fsc\$(Configuration)\$(_FSharpBuildTargetFramework) $(_FSharpBuildBinPath)\FSharp.Build.dll diff --git a/eng/Build.ps1 b/eng/Build.ps1 index 034ea1aaa6e..04bee5a40d8 100644 --- a/eng/Build.ps1 +++ b/eng/Build.ps1 @@ -65,6 +65,7 @@ function Print-Usage() { Write-Host "" Write-Host "Actions:" Write-Host " -restore Restore packages (short: -r)" + Write-Host " -norestore Don't restore packages" Write-Host " -build Build main solution (short: -b)" Write-Host " -rebuild Rebuild main solution" Write-Host " -pack Build NuGet packages, VS insertion manifests and installer" @@ -100,6 +101,7 @@ function Process-Arguments() { Print-Usage exit 0 } + $script:nodeReuse = $False; if ($testAll) { $script:testDesktop = $True @@ -126,7 +128,7 @@ function Process-Arguments() { } function Update-Arguments() { - if (-Not (Test-Path "$ArtifactsDir\Bootstrap\fsc.exe")) { + if (-Not (Test-Path "$ArtifactsDir\Bootstrap\fsc\fsc.exe")) { $script:bootstrap = $True } } @@ -160,10 +162,10 @@ function BuildSolution() { /p:Publish=$publish ` /p:ContinuousIntegrationBuild=$ci ` /p:OfficialBuildId=$officialBuildId ` - /p:BootstrapBuildPath=$bootstrapDir ` /p:QuietRestore=$quietRestore ` /p:QuietRestoreBinaryLog=$binaryLog ` /p:TestTargetFrameworks=$testTargetFrameworks ` + /v:$verbosity ` $suppressExtensionDeployment ` @properties } @@ -194,7 +196,7 @@ function UpdatePath() { } function VerifyAssemblyVersions() { - $fsiPath = Join-Path $ArtifactsDir "bin\fsi\Proto\net472\fsi.exe" + $fsiPath = Join-Path $ArtifactsDir "bin\fsi\Proto\net472\publish\fsi.exe" # Only verify versions on CI or official build if ($ci -or $official) { diff --git a/eng/build-utils.ps1 b/eng/build-utils.ps1 index d1e5dd85d55..f85a9007296 100644 --- a/eng/build-utils.ps1 +++ b/eng/build-utils.ps1 @@ -178,7 +178,7 @@ function Get-PackageDir([string]$name, [string]$version = "") { return $p } -function Run-MSBuild([string]$projectFilePath, [string]$buildArgs = "", [string]$logFileName = "", [switch]$parallel = $true, [switch]$summary = $true, [switch]$warnAsError = $true, [string]$configuration = $script:configuration) { +function Run-MSBuild([string]$projectFilePath, [string]$buildArgs = "", [string]$logFileName = "", [switch]$parallel = $true, [switch]$summary = $true, [switch]$warnAsError = $true, [string]$configuration = $script:configuration, [string]$verbosity = $script:verbosity) { # Because we override the C#/VB toolset to build against our LKG package, it is important # that we do not reuse MSBuild nodes from other jobs/builds on the machine. Otherwise, # we'll run into issues such as https://github.com/dotnet/roslyn/issues/6211. @@ -190,9 +190,9 @@ function Run-MSBuild([string]$projectFilePath, [string]$buildArgs = "", [string] } if ($summary) { - $args += " /consoleloggerparameters:Verbosity=minimal;summary" + $args += " /consoleloggerparameters:Verbosity=$verbosity;summary" } else { - $args += " /consoleloggerparameters:Verbosity=minimal" + $args += " /consoleloggerparameters:Verbosity=$verbosity" } if ($parallel) { @@ -216,10 +216,6 @@ function Run-MSBuild([string]$projectFilePath, [string]$buildArgs = "", [string] $args += " /p:ContinuousIntegrationBuild=true" } - if ($bootstrapDir -ne "") { - $args += " /p:BootstrapBuildPath=$bootstrapDir" - } - $args += " $buildArgs" $args += " $projectFilePath" $args += " $properties" @@ -241,15 +237,15 @@ function Make-BootstrapBuild() { Create-Directory $dir # prepare FsLex and Fsyacc - Run-MSBuild "$RepoRoot\src\buildtools\buildtools.proj" "/restore /t:Build" -logFileName "BuildTools" -configuration $bootstrapConfiguration - Copy-Item "$ArtifactsDir\bin\fslex\$bootstrapConfiguration\netcoreapp2.1\*" -Destination $dir - Copy-Item "$ArtifactsDir\bin\fsyacc\$bootstrapConfiguration\netcoreapp2.1\*" -Destination $dir + Run-MSBuild "$RepoRoot\src\buildtools\buildtools.proj" "/restore /t:Publish" -logFileName "BuildTools" -configuration $bootstrapConfiguration -verbosity $verbosity + Copy-Item "$ArtifactsDir\bin\fslex\$bootstrapConfiguration\netcoreapp2.1\publish" -Destination "$dir\fslex" -Force -Recurse + Copy-Item "$ArtifactsDir\bin\fsyacc\$bootstrapConfiguration\netcoreapp2.1\publish" -Destination "$dir\fsyacc" -Force -Recurse # prepare compiler $projectPath = "$RepoRoot\proto.proj" - Run-MSBuild $projectPath "/restore /t:Build" -logFileName "Bootstrap" -configuration $bootstrapConfiguration - Copy-Item "$ArtifactsDir\bin\fsc\$bootstrapConfiguration\$bootstrapTfm\*" -Destination $dir - Copy-Item "$ArtifactsDir\bin\fsi\$bootstrapConfiguration\$bootstrapTfm\*" -Destination $dir + Run-MSBuild $projectPath "/restore /t:Publish" -logFileName "Bootstrap" -configuration $bootstrapConfiguration -verbosity $verbosity + Copy-Item "$ArtifactsDir\bin\fsc\$bootstrapConfiguration\$bootstrapTfm\publish" -Destination "$dir\fsc" -Force -Recurse + Copy-Item "$ArtifactsDir\bin\fsi\$bootstrapConfiguration\$bootstrapTfm\publish" -Destination "$dir\fsi" -Force -Recurse return $dir } diff --git a/eng/build.sh b/eng/build.sh index 58b283ff39b..8a236373f37 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -13,7 +13,9 @@ usage() echo " --binaryLog Create MSBuild binary log (short: -bl)" echo "" echo "Actions:" + echo " --bootstrap Force the build of the bootstrap compiler" echo " --restore Restore projects required to build (short: -r)" + echo " --norestore Don't restore projects required to build" echo " --build Build all projects (short: -b)" echo " --rebuild Rebuild all projects" echo " --pack Build nuget packages" @@ -54,6 +56,7 @@ test_core_clr=false configuration="Debug" verbosity='minimal' binary_log=false +force_bootstrap=false ci=false skip_analyzers=false prepare_machine=false @@ -88,6 +91,9 @@ while [[ $# > 0 ]]; do --binarylog|-bl) binary_log=true ;; + --bootstrap) + force_bootstrap=true + ;; --restore|-r) restore=true ;; @@ -205,21 +211,40 @@ function BuildSolution { quiet_restore=true fi + # Node reuse fails because multiple different versions of FSharp.Build.dll get loaded into MSBuild nodes + node_reuse=false + # build bootstrap tools bootstrap_config=Proto - MSBuild "$repo_root/src/buildtools/buildtools.proj" \ - /restore \ - /p:Configuration=$bootstrap_config \ - /t:Build - bootstrap_dir=$artifacts_dir/Bootstrap - mkdir -p "$bootstrap_dir" - cp $artifacts_dir/bin/fslex/$bootstrap_config/netcoreapp2.1/* $bootstrap_dir - cp $artifacts_dir/bin/fsyacc/$bootstrap_config/netcoreapp2.1/* $bootstrap_dir + if [[ "$force_bootstrap" == true ]]; then + rm -fr $bootstrap_dir + fi + if [ ! -f "$bootstrap_dir/fslex.dll" ]; then + MSBuild "$repo_root/src/buildtools/buildtools.proj" \ + /restore \ + /v:$verbosity \ + /p:Configuration=$bootstrap_config \ + /t:Publish + + mkdir -p "$bootstrap_dir" + cp -pr $artifacts_dir/bin/fslex/$bootstrap_config/netcoreapp2.1/publish $bootstrap_dir/fslex + cp -pr $artifacts_dir/bin/fsyacc/$bootstrap_config/netcoreapp2.1/publish $bootstrap_dir/fsyacc + fi + if [ ! -f "$bootstrap_dir/fsc.exe" ]; then + MSBuild "$repo_root/proto.proj" \ + /restore \ + /v:$verbosity \ + /p:Configuration=$bootstrap_config \ + /t:Publish + + cp -pr $artifacts_dir/bin/fsc/$bootstrap_config/netcoreapp2.1/publish $bootstrap_dir/fsc + fi # do real build MSBuild $toolset_build_proj \ $bl \ + /v:$verbosity \ /p:Configuration=$configuration \ /p:Projects="$projects" \ /p:RepoRoot="$repo_root" \ diff --git a/fcs/Directory.Build.props b/fcs/Directory.Build.props index 596b06c0716..4c8aac0a5b6 100644 --- a/fcs/Directory.Build.props +++ b/fcs/Directory.Build.props @@ -20,9 +20,4 @@ $(ArtifactsObjDir)\fcs true - - - - $(ArtifactsBinDir)\FSharp.Build\Proto\net472 - diff --git a/proto.proj b/proto.proj index 84103f6fdf8..b0ee288977f 100644 --- a/proto.proj +++ b/proto.proj @@ -28,6 +28,10 @@ + + + + diff --git a/src/buildtools/buildtools.proj b/src/buildtools/buildtools.proj index 593f086dd07..630bb678561 100644 --- a/src/buildtools/buildtools.proj +++ b/src/buildtools/buildtools.proj @@ -2,7 +2,8 @@ Debug - + true + @@ -10,23 +11,23 @@ - + - + - + - + - + diff --git a/src/buildtools/buildtools.targets b/src/buildtools/buildtools.targets index 303ab00825d..185fd4d0599 100644 --- a/src/buildtools/buildtools.targets +++ b/src/buildtools/buildtools.targets @@ -20,7 +20,7 @@ BeforeTargets="CoreCompile"> - $(ArtifactsDir)\Bootstrap\fslex.dll + $(ArtifactsDir)\Bootstrap\fslex\fslex.dll @@ -43,7 +43,7 @@ BeforeTargets="CoreCompile"> - $(ArtifactsDir)\Bootstrap\fsyacc.dll + $(ArtifactsDir)\Bootstrap\fsyacc\fsyacc.dll diff --git a/src/fsharp/ConstraintSolver.fs b/src/fsharp/ConstraintSolver.fs index a372de41e11..30c22a867c8 100644 --- a/src/fsharp/ConstraintSolver.fs +++ b/src/fsharp/ConstraintSolver.fs @@ -2752,112 +2752,29 @@ let AddCxTypeIsDelegate denv css m trace ty aty bty = (fun res -> ErrorD (ErrorFromAddingConstraint(denv, res, m))) |> RaiseOperationResult -let CodegenWitnessThatTypeSupportsTraitConstraint tcVal g amap m (traitInfo: TraitConstraintInfo) argExprs = trackErrors { - let css = - { g = g - amap = amap - TcVal = tcVal - ExtraCxs = HashMultiMap(10, HashIdentity.Structural) - InfoReader = new InfoReader(g, amap) } - +let CreateCodegenState tcVal g amap = + { g = g + amap = amap + TcVal = tcVal + ExtraCxs = HashMultiMap(10, HashIdentity.Structural) + InfoReader = new InfoReader(g, amap) } + +let CodegenWitnessForTraitConstraint tcVal g amap m (traitInfo:TraitConstraintInfo) argExprs = trackErrors { + let css = CreateCodegenState tcVal g amap let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m (DisplayEnv.Empty g) let! _res = SolveMemberConstraint csenv true true 0 m NoTrace traitInfo - let sln = - match traitInfo.Solution with - | None -> Choice5Of5() - | Some sln -> - match sln with - | ILMethSln(origTy, extOpt, mref, minst) -> - let metadataTy = convertToTypeWithMetadataIfPossible g origTy - let tcref = tcrefOfAppTy g metadataTy - let mdef = IL.resolveILMethodRef tcref.ILTyconRawMetadata mref - let ilMethInfo = - match extOpt with - | None -> MethInfo.CreateILMeth(amap, m, origTy, mdef) - | Some ilActualTypeRef -> - let actualTyconRef = Import.ImportILTypeRef amap m ilActualTypeRef - MethInfo.CreateILExtensionMeth(amap, m, origTy, actualTyconRef, None, mdef) - Choice1Of5 (ilMethInfo, minst) - | FSMethSln(ty, vref, minst) -> - Choice1Of5 (FSMeth(g, ty, vref, None), minst) - | FSRecdFieldSln(tinst, rfref, isSetProp) -> - Choice2Of5 (tinst, rfref, isSetProp) - | FSAnonRecdFieldSln(anonInfo, tinst, i) -> - Choice3Of5 (anonInfo, tinst, i) - | BuiltInSln -> - Choice5Of5 () - | ClosedExprSln expr -> - Choice4Of5 expr - return! - match sln with - | Choice1Of5(minfo, methArgTys) -> - let argExprs = - // FIX for #421894 - typechecker assumes that coercion can be applied for the trait calls arguments but codegen doesn't emit coercion operations - // result - generation of non-verifyable code - // fix - apply coercion for the arguments (excluding 'receiver' argument in instance calls) - - // flatten list of argument types (looks like trait calls with curried arguments are not supported so we can just convert argument list in straighforward way) - let argTypes = - minfo.GetParamTypes(amap, m, methArgTys) - |> List.concat - // do not apply coercion to the 'receiver' argument - let receiverArgOpt, argExprs = - if minfo.IsInstance then - match argExprs with - | h :: t -> Some h, t - | argExprs -> None, argExprs - else None, argExprs - let convertedArgs = (argExprs, argTypes) ||> List.map2 (fun expr expectedTy -> mkCoerceIfNeeded g expectedTy (tyOfExpr g expr) expr) - match receiverArgOpt with - | Some r -> r :: convertedArgs - | None -> convertedArgs - - // Fix bug 1281: If we resolve to an instance method on a struct and we haven't yet taken - // the address of the object then go do that - if minfo.IsStruct && minfo.IsInstance && (match argExprs with [] -> false | h :: _ -> not (isByrefTy g (tyOfExpr g h))) then - let h, t = List.headAndTail argExprs - let wrap, h', _readonly, _writeonly = mkExprAddrOfExpr g true false PossiblyMutates h None m - ResultD (Some (wrap (Expr.Op (TOp.TraitCall (traitInfo), [], (h' :: t), m)))) - else - ResultD (Some (MakeMethInfoCall amap m minfo methArgTys argExprs )) - - | Choice2Of5 (tinst, rfref, isSet) -> - let res = - match isSet, rfref.RecdField.IsStatic, argExprs.Length with - | true, true, 1 -> - Some (mkStaticRecdFieldSet (rfref, tinst, argExprs.[0], m)) - | true, false, 2 -> - // If we resolve to an instance field on a struct and we haven't yet taken - // the address of the object then go do that - if rfref.Tycon.IsStructOrEnumTycon && not (isByrefTy g (tyOfExpr g argExprs.[0])) then - let h = List.head argExprs - let wrap, h', _readonly, _writeonly = mkExprAddrOfExpr g true false DefinitelyMutates h None m - Some (wrap (mkRecdFieldSetViaExprAddr (h', rfref, tinst, argExprs.[1], m))) - else - Some (mkRecdFieldSetViaExprAddr (argExprs.[0], rfref, tinst, argExprs.[1], m)) - | false, true, 0 -> - Some (mkStaticRecdFieldGet (rfref, tinst, m)) - | false, false, 1 -> - if rfref.Tycon.IsStructOrEnumTycon && isByrefTy g (tyOfExpr g argExprs.[0]) then - Some (mkRecdFieldGetViaExprAddr (argExprs.[0], rfref, tinst, m)) - else - Some (mkRecdFieldGet g (argExprs.[0], rfref, tinst, m)) - | _ -> None - ResultD res - | Choice3Of5 (anonInfo, tinst, i) -> - let res = - let tupInfo = anonInfo.TupInfo - if evalTupInfoIsStruct tupInfo && isByrefTy g (tyOfExpr g argExprs.[0]) then - Some (mkAnonRecdFieldGetViaExprAddr (anonInfo, argExprs.[0], tinst, i, m)) - else - Some (mkAnonRecdFieldGet g (anonInfo, argExprs.[0], tinst, i, m)) - ResultD res - - | Choice4Of5 expr -> ResultD (Some (MakeApplicationAndBetaReduce g (expr, tyOfExpr g expr, [], argExprs, m))) - - | Choice5Of5 () -> ResultD None + let sln = GenWitnessExpr amap g m traitInfo argExprs + return sln } +let CodegenWitnessesForTyparInst tcVal g amap m typars tyargs = trackErrors { + let css = CreateCodegenState tcVal g amap + let csenv = MakeConstraintSolverEnv ContextInfo.NoContext css m (DisplayEnv.Empty g) + let ftps, _renaming, tinst = FreshenTypeInst m typars + let cxs = GetTraitConstraintInfosOfTypars g ftps + do! SolveTypeEqualsTypeEqns csenv 0 m NoTrace None tinst tyargs + return MethodCalls.GenNonGenericWitnessArgs amap g m cxs + } let ChooseTyparSolutionAndSolve css denv tp = let g = css.g diff --git a/src/fsharp/ConstraintSolver.fsi b/src/fsharp/ConstraintSolver.fsi index 4626c736bdb..43e96302774 100644 --- a/src/fsharp/ConstraintSolver.fsi +++ b/src/fsharp/ConstraintSolver.fsi @@ -140,7 +140,9 @@ val AddCxTypeIsUnmanaged : DisplayEnv -> ConstraintSolverSt val AddCxTypeIsEnum : DisplayEnv -> ConstraintSolverState -> range -> OptionalTrace -> TType -> TType -> unit val AddCxTypeIsDelegate : DisplayEnv -> ConstraintSolverState -> range -> OptionalTrace -> TType -> TType -> TType -> unit -val CodegenWitnessThatTypeSupportsTraitConstraint : TcValF -> TcGlobals -> ImportMap -> range -> TraitConstraintInfo -> Expr list -> OperationResult +val CodegenWitnessForTraitConstraint : TcValF -> TcGlobals -> ImportMap -> range -> TraitConstraintInfo -> Expr list -> OperationResult + +val CodegenWitnessesForTyparInst : TcValF -> TcGlobals -> ImportMap -> range -> Typars -> TType list -> OperationResult list> val ChooseTyparSolutionAndSolve : ConstraintSolverState -> DisplayEnv -> Typar -> unit diff --git a/src/fsharp/FSharp.Build/FSharp.Build.fsproj b/src/fsharp/FSharp.Build/FSharp.Build.fsproj index 0dad55058b0..17170e751d0 100644 --- a/src/fsharp/FSharp.Build/FSharp.Build.fsproj +++ b/src/fsharp/FSharp.Build/FSharp.Build.fsproj @@ -32,6 +32,7 @@ + diff --git a/src/fsharp/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj b/src/fsharp/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj index 6307f17baf3..5bc96e7ed2d 100644 --- a/src/fsharp/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj +++ b/src/fsharp/FSharp.Compiler.Interactive.Settings/FSharp.Compiler.Interactive.Settings.fsproj @@ -27,6 +27,7 @@ + diff --git a/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj b/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj index 9fef6d27589..b7ba0a23cd8 100644 --- a/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj +++ b/src/fsharp/FSharp.Compiler.Private/FSharp.Compiler.Private.fsproj @@ -674,6 +674,7 @@ + diff --git a/src/fsharp/FSharp.Compiler.Server.Shared/FSharp.Compiler.Server.Shared.fsproj b/src/fsharp/FSharp.Compiler.Server.Shared/FSharp.Compiler.Server.Shared.fsproj index 75a7353bb96..8bd027a0623 100644 --- a/src/fsharp/FSharp.Compiler.Server.Shared/FSharp.Compiler.Server.Shared.fsproj +++ b/src/fsharp/FSharp.Compiler.Server.Shared/FSharp.Compiler.Server.Shared.fsproj @@ -20,6 +20,7 @@ + diff --git a/src/fsharp/FSharp.Core/Linq.fs b/src/fsharp/FSharp.Core/Linq.fs index 68e8fde5fe6..da355578e97 100644 --- a/src/fsharp/FSharp.Core/Linq.fs +++ b/src/fsharp/FSharp.Core/Linq.fs @@ -249,119 +249,128 @@ module LeafExpressionConverter = let minfo = (System.Reflection.MethodInfo.GetMethodFromHandle mhandle) :?> MethodInfo SpecificCallToMethodInfo minfo - let (|GenericEqualityQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> LanguagePrimitives.GenericEquality x y)) - let (|EqualsQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x = y)) - let (|GreaterQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x > y)) - let (|GreaterEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x >= y)) - let (|LessQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x < y)) - let (|LessEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x <= y)) - let (|NotEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x <> y)) - - let (|StaticEqualsQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int, y:int) -> NonStructuralComparison.(=) x y)) - let (|StaticGreaterQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int, y:int) -> NonStructuralComparison.(>) x y)) - let (|StaticGreaterEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int, y:int) -> NonStructuralComparison.(>=) x y)) - let (|StaticLessQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int, y:int) -> NonStructuralComparison.(<) x y)) - let (|StaticLessEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int, y:int) -> NonStructuralComparison.(<=) x y)) - let (|StaticNotEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int, y:int) -> NonStructuralComparison.(<>) x y)) - - let (|NullableEqualsQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?= ) x y)) - let (|NullableNotEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?<> ) x y)) - let (|NullableGreaterQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?> ) x y)) - let (|NullableGreaterEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?>= ) x y)) - let (|NullableLessQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?< ) x y)) - let (|NullableLessEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?<= ) x y)) - - let (|NullableEqualsNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?=? ) x y)) - let (|NullableNotEqNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?<>? ) x y)) - let (|NullableGreaterNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?>? ) x y)) - let (|NullableGreaterEqNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?>=? ) x y)) - let (|NullableLessNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ? NullableOperators.( ?<=? ) x y)) - - let (|EqualsNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( =? ) x y)) - let (|NotEqNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( <>? ) x y)) - let (|GreaterNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( >? ) x y)) - let (|GreaterEqNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( >=? ) x y)) - let (|LessNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( NullableOperators.( <=? ) x y)) - - let (|MakeDecimalQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (a1, a2, a3, a4, a5) -> LanguagePrimitives.IntrinsicFunctions.MakeDecimal a1 a2 a3 a4 a5)) - - let (|NullablePlusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?+ ) x y)) - let (|NullablePlusNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?+? ) x y)) - let (|PlusNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( +? ) x y)) - - let (|NullableMinusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?- ) x y)) - let (|NullableMinusNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?-? ) x y)) - let (|MinusNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( -? ) x y)) - - let (|NullableMultiplyQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?* ) x y)) - let (|NullableMultiplyNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?*? ) x y)) - let (|MultiplyNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( *? ) x y)) - - let (|NullableDivideQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?/ ) x y)) - let (|NullableDivideNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?/? ) x y)) - let (|DivideNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( /? ) x y)) - - let (|NullableModuloQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?% ) x y)) - let (|NullableModuloNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( ?%? ) x y)) - let (|ModuloNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> NullableOperators.( %? ) x y)) - - let (|NotQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> not x)) - let (|NegQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int) -> -x)) - let (|PlusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x + y)) - let (|DivideQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x / y)) - let (|MinusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x - y)) - let (|MultiplyQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x * y)) - let (|ModuloQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x % y)) - let (|ShiftLeftQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x <<< y)) - let (|ShiftRightQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x >>> y)) - let (|BitwiseAndQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x &&& y)) - let (|BitwiseOrQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x ||| y)) - let (|BitwiseXorQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> x ^^^ y)) - let (|BitwiseNotQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> ~~~ x)) - let (|CheckedNeg|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Checked.( ~-) x)) - let (|CheckedPlusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> Checked.( + ) x y)) - let (|CheckedMinusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> Checked.( - ) x y)) - let (|CheckedMultiplyQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x, y) -> Checked.( * ) x y)) - - let (|ConvCharQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.char x)) - let (|ConvDecimalQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.decimal x)) - let (|ConvFloatQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.float x)) - let (|ConvFloat32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.float32 x)) - let (|ConvSByteQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.sbyte x)) - - let (|ConvInt16Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.int16 x)) - let (|ConvInt32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.int32 x)) - let (|ConvIntQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.int x)) - let (|ConvInt64Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.int64 x)) - let (|ConvByteQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.byte x)) - let (|ConvUInt16Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.uint16 x)) - let (|ConvUInt32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.uint32 x)) - let (|ConvUInt64Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.uint64 x)) - - let (|ConvInt8Q|_|) = SpecificCallToMethodInfo (typeof.Assembly.GetType("Microsoft.FSharp.Core.ExtraTopLevelOperators").GetMethod("ToSByte")) - let (|ConvUInt8Q|_|) = SpecificCallToMethodInfo (typeof.Assembly.GetType("Microsoft.FSharp.Core.ExtraTopLevelOperators").GetMethod("ToByte")) - let (|ConvDoubleQ|_|) = SpecificCallToMethodInfo (typeof.Assembly.GetType("Microsoft.FSharp.Core.ExtraTopLevelOperators").GetMethod("ToDouble")) - let (|ConvSingleQ|_|) = SpecificCallToMethodInfo (typeof.Assembly.GetType("Microsoft.FSharp.Core.ExtraTopLevelOperators").GetMethod("ToSingle")) - - let (|ConvNullableCharQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.char x)) - let (|ConvNullableDecimalQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.decimal x)) - let (|ConvNullableFloatQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.float x)) - let (|ConvNullableDoubleQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.double x)) - let (|ConvNullableFloat32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.float32 x)) - let (|ConvNullableSingleQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.single x)) - let (|ConvNullableSByteQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.sbyte x)) - let (|ConvNullableInt8Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.int8 x)) - let (|ConvNullableInt16Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.int16 x)) - let (|ConvNullableInt32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.int32 x)) - let (|ConvNullableIntQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.int x)) - let (|ConvNullableInt64Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.int64 x)) - let (|ConvNullableByteQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.byte x)) - let (|ConvNullableUInt8Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.uint8 x)) - let (|ConvNullableUInt16Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.uint16 x)) - let (|ConvNullableUInt32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.uint32 x)) - let (|ConvNullableUInt64Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.uint64 x)) + let (|GenericEqualityQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> LanguagePrimitives.GenericEquality x y)) + let (|EqualsQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x = y)) + let (|GreaterQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x > y)) + let (|GreaterEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x >= y)) + let (|LessQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x < y)) + let (|LessEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x <= y)) + let (|NotEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x <> y)) + + let (|StaticEqualsQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(=) x y)) + let (|StaticGreaterQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(>) x y)) + let (|StaticGreaterEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(>=) x y)) + let (|StaticLessQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(<) x y)) + let (|StaticLessEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(<=) x y)) + let (|StaticNotEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int,y:int) -> NonStructuralComparison.(<>) x y)) + + let (|NullableEqualsQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?= ) x y)) + let (|NullableNotEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?<> ) x y)) + let (|NullableGreaterQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?> ) x y)) + let (|NullableGreaterEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?>= ) x y)) + let (|NullableLessQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?< ) x y)) + let (|NullableLessEqQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?<= ) x y)) + + let (|NullableEqualsNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?=? ) x y)) + let (|NullableNotEqNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?<>? ) x y)) + let (|NullableGreaterNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?>? ) x y)) + let (|NullableGreaterEqNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?>=? ) x y)) + let (|NullableLessNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ? NullableOperators.( ?<=? ) x y)) + + let (|EqualsNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( =? ) x y)) + let (|NotEqNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( <>? ) x y)) + let (|GreaterNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( >? ) x y)) + let (|GreaterEqNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( >=? ) x y)) + let (|LessNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( NullableOperators.( <=? ) x y)) + + let (|MakeDecimalQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (a1,a2,a3,a4,a5) -> LanguagePrimitives.IntrinsicFunctions.MakeDecimal a1 a2 a3 a4 a5)) + + + let (|NullablePlusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?+ ) x y)) + let (|NullablePlusNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?+? ) x y)) + let (|PlusNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( +? ) x y)) + + let (|NullableMinusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?- ) x y)) + let (|NullableMinusNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?-? ) x y)) + let (|MinusNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( -? ) x y)) + + let (|NullableMultiplyQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?* ) x y)) + let (|NullableMultiplyNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?*? ) x y)) + let (|MultiplyNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( *? ) x y)) + + let (|NullableDivideQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?/ ) x y)) + let (|NullableDivideNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?/? ) x y)) + let (|DivideNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( /? ) x y)) + + let (|NullableModuloQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?% ) x y)) + let (|NullableModuloNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( ?%? ) x y)) + let (|ModuloNullableQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> NullableOperators.( %? ) x y)) + + let (|NotQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> not x)) + let (|NegQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x:int) -> -x)) + let (|PlusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x + y)) + let (|DivideQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x / y)) + let (|MinusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x - y)) + let (|MultiplyQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x * y)) + let (|ModuloQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x % y)) + let (|ShiftLeftQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x <<< y)) + let (|ShiftRightQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x >>> y)) + let (|BitwiseAndQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x &&& y)) + let (|BitwiseOrQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x ||| y)) + let (|BitwiseXorQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> x ^^^ y)) + let (|BitwiseNotQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> ~~~ x)) + let (|CheckedNeg|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Checked.( ~-) x)) + let (|CheckedPlusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> Checked.( + ) x y)) + let (|CheckedMinusQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> Checked.( - ) x y)) + let (|CheckedMultiplyQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun (x,y) -> Checked.( * ) x y)) + + let (|ConvCharQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.char x)) + let (|ConvDecimalQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.decimal x)) + let (|ConvFloatQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.float x)) + let (|ConvFloat32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.float32 x)) + let (|ConvSByteQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.sbyte x)) + + + let (|ConvInt16Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.int16 x)) + let (|ConvInt32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.int32 x)) + let (|ConvIntQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.int x)) + let (|ConvInt64Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.int64 x)) + let (|ConvByteQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.byte x)) + let (|ConvUInt16Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.uint16 x)) + let (|ConvUInt32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.uint32 x)) + let (|ConvUInt64Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Operators.uint64 x)) + + /// Get the version of the method that does not carry witnesses + let nonWitnessMethodInfo nm (ms: MethodInfo[]) = + ms |> Array.pick (fun m -> if m.Name = nm && m.GetParameters().Length = 1 then Some m else None) + + let ExtraOperatorsTy = typeof.Assembly.GetType("Microsoft.FSharp.Core.ExtraTopLevelOperators") + let ExtraOperatorsCheckedTy = typeof.Assembly.GetType("Microsoft.FSharp.Core.ExtraTopLevelOperators+Checked") + + let (|ConvInt8Q|_|) = SpecificCallToMethodInfo (ExtraOperatorsTy.GetMethods() |> nonWitnessMethodInfo "ToSByte") + let (|ConvUInt8Q|_|) = SpecificCallToMethodInfo (ExtraOperatorsTy.GetMethods() |> nonWitnessMethodInfo "ToByte") + let (|ConvDoubleQ|_|) = SpecificCallToMethodInfo (ExtraOperatorsTy.GetMethods() |> nonWitnessMethodInfo "ToDouble") + let (|ConvSingleQ|_|) = SpecificCallToMethodInfo (ExtraOperatorsTy.GetMethods() |> nonWitnessMethodInfo "ToSingle") + + let (|ConvNullableCharQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.char x)) + let (|ConvNullableDecimalQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.decimal x)) + let (|ConvNullableFloatQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.float x)) + let (|ConvNullableDoubleQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.double x)) + let (|ConvNullableFloat32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.float32 x)) + let (|ConvNullableSingleQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.single x)) + let (|ConvNullableSByteQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.sbyte x)) + let (|ConvNullableInt8Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.int8 x)) + let (|ConvNullableInt16Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.int16 x)) + let (|ConvNullableInt32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.int32 x)) + let (|ConvNullableIntQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.int x)) + let (|ConvNullableInt64Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.int64 x)) + let (|ConvNullableByteQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.byte x)) + let (|ConvNullableUInt8Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.uint8 x)) + let (|ConvNullableUInt16Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.uint16 x)) + let (|ConvNullableUInt32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.uint32 x)) + let (|ConvNullableUInt64Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.uint64 x)) // LINQ expressions can't do native integer operations, so we don't convert these //let (|ConvNullableIntPtrQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.nativeint x)) //let (|ConvNullableUIntPtrQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Nullable.unativeint x)) @@ -371,8 +380,8 @@ module LeafExpressionConverter = let (|TypeTestGeneric|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> LanguagePrimitives.IntrinsicFunctions.TypeTestGeneric x)) let (|CheckedConvCharQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Checked.char x)) let (|CheckedConvSByteQ|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Checked.sbyte x)) - let (|CheckedConvInt8Q|_|) = SpecificCallToMethodInfo (typeof.Assembly.GetType("Microsoft.FSharp.Core.ExtraTopLevelOperators+Checked").GetMethod("ToSByte")) - let (|CheckedConvUInt8Q|_|) = SpecificCallToMethodInfo (typeof.Assembly.GetType("Microsoft.FSharp.Core.ExtraTopLevelOperators+Checked").GetMethod("ToByte")) + let (|CheckedConvInt8Q|_|) = SpecificCallToMethodInfo (ExtraOperatorsCheckedTy.GetMethods() |> nonWitnessMethodInfo "ToSByte") + let (|CheckedConvUInt8Q|_|) = SpecificCallToMethodInfo (ExtraOperatorsCheckedTy.GetMethods() |> nonWitnessMethodInfo "ToByte") let (|CheckedConvInt16Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Checked.int16 x)) let (|CheckedConvInt32Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Checked.int32 x)) let (|CheckedConvInt64Q|_|) = (|SpecificCallToMethod|_|) (methodhandleof (fun x -> Checked.int64 x)) @@ -508,94 +517,92 @@ module LeafExpressionConverter = let argsR = ConvExprsToLinq env args let props = ctor.DeclaringType.GetProperties() Expression.New(ctor, argsR, [| for p in props -> (p :> MemberInfo) |]) |> asExpr - - - // Do the same thing as C# compiler for string addition - | PlusQ (_, [ty1; ty2; ty3], [x1; x2]) when (ty1 = typeof) && (ty2 = typeof) && (ty3 = typeof) -> + + // Do the same thing as C# compiler for string addition + | PlusQ (_, [ty1;ty2;ty3],[x1;x2]) when (ty1 = typeof) && (ty2 = typeof) && (ty3 = typeof) -> Expression.Add(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2, StringConcat) |> asExpr - | GenericEqualityQ (_, _, [x1; x2]) - | EqualsQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.Equal - | NotEqQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.NotEqual - | GreaterQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.GreaterThan - | GreaterEqQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.GreaterThanOrEqual - | LessQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.LessThan - | LessEqQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.LessThanOrEqual - | NotQ (_, _, [x1]) -> Expression.Not(ConvExprToLinqInContext env x1) |> asExpr - - | StaticEqualsQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.Equal - | StaticNotEqQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.NotEqual - | StaticGreaterQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.GreaterThan - | StaticGreaterEqQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.GreaterThanOrEqual - | StaticLessQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.LessThan - | StaticLessEqQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.LessThanOrEqual - - | NullableEqualsQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.Equal - | NullableNotEqQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.NotEqual - | NullableGreaterQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.GreaterThan - | NullableGreaterEqQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.GreaterThanOrEqual - | NullableLessQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.LessThan - | NullableLessEqQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.LessThanOrEqual - - | EqualsNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.Equal - | NotEqNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.NotEqual - | GreaterNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.GreaterThan - | GreaterEqNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.GreaterThanOrEqual - | LessNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.LessThan - | LessEqNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.LessThanOrEqual - - | NullableEqualsNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.Equal - | NullableNotEqNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.NotEqual - | NullableGreaterNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.GreaterThan - | NullableGreaterEqNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.GreaterThanOrEqual - | NullableLessNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.LessThan - | NullableLessEqNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.LessThanOrEqual - + | GenericEqualityQ _ + | EqualsQ _ -> transBinOp env false args false Expression.Equal + | NotEqQ _ -> transBinOp env false args false Expression.NotEqual + | GreaterQ _ -> transBinOp env false args false Expression.GreaterThan + | GreaterEqQ _ -> transBinOp env false args false Expression.GreaterThanOrEqual + | LessQ _ -> transBinOp env false args false Expression.LessThan + | LessEqQ _ -> transBinOp env false args false Expression.LessThanOrEqual + | NotQ (_, _, [x1]) -> Expression.Not(ConvExprToLinqInContext env x1) |> asExpr + + | StaticEqualsQ _ -> transBinOp env false args false Expression.Equal + | StaticNotEqQ _ -> transBinOp env false args false Expression.NotEqual + | StaticGreaterQ _ -> transBinOp env false args false Expression.GreaterThan + | StaticGreaterEqQ _ -> transBinOp env false args false Expression.GreaterThanOrEqual + | StaticLessQ _ -> transBinOp env false args false Expression.LessThan + | StaticLessEqQ _ -> transBinOp env false args false Expression.LessThanOrEqual + + | NullableEqualsQ _ -> transBinOp env false args true Expression.Equal + | NullableNotEqQ _ -> transBinOp env false args true Expression.NotEqual + | NullableGreaterQ _ -> transBinOp env false args true Expression.GreaterThan + | NullableGreaterEqQ _ -> transBinOp env false args true Expression.GreaterThanOrEqual + | NullableLessQ _ -> transBinOp env false args true Expression.LessThan + | NullableLessEqQ _ -> transBinOp env false args true Expression.LessThanOrEqual + + | EqualsNullableQ _ -> transBinOp env true args false Expression.Equal + | NotEqNullableQ _ -> transBinOp env true args false Expression.NotEqual + | GreaterNullableQ _ -> transBinOp env true args false Expression.GreaterThan + | GreaterEqNullableQ _ -> transBinOp env true args false Expression.GreaterThanOrEqual + | LessNullableQ _ -> transBinOp env true args false Expression.LessThan + | LessEqNullableQ _ -> transBinOp env true args false Expression.LessThanOrEqual + + | NullableEqualsNullableQ _ -> transBinOp env false args false Expression.Equal + | NullableNotEqNullableQ _ -> transBinOp env false args false Expression.NotEqual + | NullableGreaterNullableQ _ -> transBinOp env false args false Expression.GreaterThan + | NullableGreaterEqNullableQ _ -> transBinOp env false args false Expression.GreaterThanOrEqual + | NullableLessNullableQ _ -> transBinOp env false args false Expression.LessThan + | NullableLessEqNullableQ _ -> transBinOp env false args false Expression.LessThanOrEqual + // Detect the F# quotation encoding of decimal literals - | MakeDecimalQ (_, _, [Int32 lo; Int32 med; Int32 hi; Bool isNegative; Byte scale]) -> - Expression.Constant (new System.Decimal(lo, med, hi, isNegative, scale)) |> asExpr - - | NegQ (_, _, [x1]) -> Expression.Negate(ConvExprToLinqInContext env x1) |> asExpr - | PlusQ (_, _, [x1; x2]) -> Expression.Add(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - | DivideQ (_, _, [x1; x2]) -> Expression.Divide (ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - | MinusQ (_, _, [x1; x2]) -> Expression.Subtract(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - | MultiplyQ (_, _, [x1; x2]) -> Expression.Multiply(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - | ModuloQ (_, _, [x1; x2]) -> Expression.Modulo (ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - - | ShiftLeftQ (_, _, [x1; x2]) -> Expression.LeftShift(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - | ShiftRightQ (_, _, [x1; x2]) -> Expression.RightShift(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - | BitwiseAndQ (_, _, [x1; x2]) -> Expression.And(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - | BitwiseOrQ (_, _, [x1; x2]) -> Expression.Or(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - | BitwiseXorQ (_, _, [x1; x2]) -> Expression.ExclusiveOr(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr + | MakeDecimalQ (_, _, [Int32 lo; Int32 med; Int32 hi; Bool isNegative; Byte scale]) -> + Expression.Constant(new System.Decimal(lo,med,hi,isNegative,scale)) |> asExpr + + | NegQ (_, _, [x1]) -> Expression.Negate(ConvExprToLinqInContext env x1) |> asExpr + | PlusQ _ -> transBinOp env false args false Expression.Add + | DivideQ _ -> transBinOp env false args false Expression.Divide + | MinusQ _ -> transBinOp env false args false Expression.Subtract + | MultiplyQ _ -> transBinOp env false args false Expression.Multiply + | ModuloQ _ -> transBinOp env false args false Expression.Modulo + + | ShiftLeftQ _ -> transBinOp env false args false Expression.LeftShift + | ShiftRightQ _ -> transBinOp env false args false Expression.RightShift + | BitwiseAndQ _ -> transBinOp env false args false Expression.And + | BitwiseOrQ _ -> transBinOp env false args false Expression.Or + | BitwiseXorQ _ -> transBinOp env false args false Expression.ExclusiveOr | BitwiseNotQ (_, _, [x1]) -> Expression.Not(ConvExprToLinqInContext env x1) |> asExpr - - | CheckedNeg (_, _, [x1]) -> Expression.NegateChecked(ConvExprToLinqInContext env x1) |> asExpr - | CheckedPlusQ (_, _, [x1; x2]) -> Expression.AddChecked(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - | CheckedMinusQ (_, _, [x1; x2]) -> Expression.SubtractChecked(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - | CheckedMultiplyQ (_, _, [x1; x2]) -> Expression.MultiplyChecked(ConvExprToLinqInContext env x1, ConvExprToLinqInContext env x2) |> asExpr - - - | NullablePlusQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.Add - | PlusNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.Add - | NullablePlusNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.Add - - | NullableMinusQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.Subtract - | MinusNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.Subtract - | NullableMinusNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.Subtract - - | NullableMultiplyQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.Multiply - | MultiplyNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.Multiply - | NullableMultiplyNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.Multiply - - | NullableDivideQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.Divide - | DivideNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.Divide - | NullableDivideNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.Divide - - | NullableModuloQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 true Expression.Modulo - | ModuloNullableQ (_, _, [x1; x2]) -> transBinOp env true x1 x2 false Expression.Modulo - | NullableModuloNullableQ (_, _, [x1; x2]) -> transBinOp env false x1 x2 false Expression.Modulo - - | ConvNullableCharQ (_, _, [x1]) -> Expression.Convert(ConvExprToLinqInContext env x1, typeof>) |> asExpr + + | CheckedNeg (_, _, [x1]) -> Expression.NegateChecked(ConvExprToLinqInContext env x1) |> asExpr + | CheckedPlusQ _ -> transBinOp env false args false Expression.AddChecked + | CheckedMinusQ _ -> transBinOp env false args false Expression.SubtractChecked + | CheckedMultiplyQ _ -> transBinOp env false args false Expression.MultiplyChecked + + | NullablePlusQ _ -> transBinOp env false args true Expression.Add + | PlusNullableQ _ -> transBinOp env true args false Expression.Add + | NullablePlusNullableQ _ -> transBinOp env false args false Expression.Add + + | NullableMinusQ _ -> transBinOp env false args true Expression.Subtract + | MinusNullableQ _ -> transBinOp env true args false Expression.Subtract + | NullableMinusNullableQ _ -> transBinOp env false args false Expression.Subtract + + | NullableMultiplyQ _ -> transBinOp env false args true Expression.Multiply + | MultiplyNullableQ _ -> transBinOp env true args false Expression.Multiply + | NullableMultiplyNullableQ _ -> transBinOp env false args false Expression.Multiply + + | NullableDivideQ _ -> transBinOp env false args true Expression.Divide + | DivideNullableQ _ -> transBinOp env true args false Expression.Divide + | NullableDivideNullableQ _ -> transBinOp env false args false Expression.Divide + + | NullableModuloQ _ -> transBinOp env false args true Expression.Modulo + | ModuloNullableQ _ -> transBinOp env true args false Expression.Modulo + | NullableModuloNullableQ _ -> transBinOp env false args false Expression.Modulo + + | ConvNullableCharQ (_, _, [x1]) -> Expression.Convert(ConvExprToLinqInContext env x1, typeof>) |> asExpr | ConvNullableDecimalQ (_, _, [x1]) -> Expression.Convert(ConvExprToLinqInContext env x1, typeof>) |> asExpr | ConvNullableFloatQ (_, _, [x1]) -> Expression.Convert(ConvExprToLinqInContext env x1, typeof>) |> asExpr | ConvNullableDoubleQ (_, _, [x1]) -> Expression.Convert(ConvExprToLinqInContext env x1, typeof>) |> asExpr @@ -651,10 +658,18 @@ module LeafExpressionConverter = // Throw away markers inserted to satisfy C#'s design where they pass an argument // or type T to an argument expecting Expression. | ImplicitExpressionConversionHelperQ (_, [_], [x1]) -> ConvExprToLinqInContext env x1 - - | _ -> - let argsP = ConvExprsToLinq env args - Expression.Call(ConvObjArg env objOpt None, minfo, argsP) |> asExpr + + | CallWithWitnesses (objArgOpt, _, minfo2, witnessArgs, args) -> + let fullArgs = witnessArgs @ args + let replacementExpr = + match objArgOpt with + | None -> Expr.Call(minfo2, fullArgs) + | Some objArg -> Expr.Call(objArg, minfo2, fullArgs) + ConvExprToLinqInContext env replacementExpr + + | _ -> + let argsP = ConvExprsToLinq env args + Expression.Call(ConvObjArg env objOpt None, minfo, argsP) |> asExpr #if !NO_CURRIED_FUNCTION_OPTIMIZATIONS // f x1 x2 x3 x4 --> InvokeFast4 @@ -804,13 +819,15 @@ module LeafExpressionConverter = | _ -> raise (new NotSupportedException(Printf.sprintf "Could not convert the following F# Quotation to a LINQ Expression Tree\n--------\n%A\n-------------\n" inp)) - and transBinOp env addConvertLeft x1 x2 addConvertRight (exprErasedConstructor : _ * _ -> _) = - let e1 = ConvExprToLinqInContext env x1 - let e2 = ConvExprToLinqInContext env x2 - let e1 = if addConvertLeft then Expression.Convert(e1, typedefof>.MakeGenericType [| e1.Type |]) |> asExpr else e1 - let e2 = if addConvertRight then Expression.Convert(e2, typedefof>.MakeGenericType [| e2.Type |]) |> asExpr else e2 - exprErasedConstructor(e1, e2) |> asExpr - + and transBinOp env addConvertLeft args addConvertRight (exprErasedConstructor : _ * _ -> _) = + match args with + | [x1; x2] -> + let e1 = ConvExprToLinqInContext env x1 + let e2 = ConvExprToLinqInContext env x2 + let e1 = if addConvertLeft then Expression.Convert(e1, typedefof>.MakeGenericType [| e1.Type |]) |> asExpr else e1 + let e2 = if addConvertRight then Expression.Convert(e2, typedefof>.MakeGenericType [| e2.Type |]) |> asExpr else e2 + exprErasedConstructor(e1, e2) |> asExpr + | _ -> raise (new NotSupportedException(Printf.sprintf "unexpected missing args in binary operator")) and ConvObjArg env objOpt coerceTo : Expression = match objOpt with diff --git a/src/fsharp/FSharp.Core/prim-types.fs b/src/fsharp/FSharp.Core/prim-types.fs index 2e91dec124f..e048af1e72d 100644 --- a/src/fsharp/FSharp.Core/prim-types.fs +++ b/src/fsharp/FSharp.Core/prim-types.fs @@ -301,10 +301,15 @@ namespace Microsoft.FSharp.Core [] [] - type NoDynamicInvocationAttribute() = + type NoDynamicInvocationAttribute(legacy: bool) = + inherit System.Attribute() - [] + new () = NoDynamicInvocationAttribute(false) + + member x.IsLegacy = legacy + + [] [] type OptionalArgumentAttribute() = inherit System.Attribute() @@ -388,8 +393,8 @@ namespace Microsoft.FSharp.Core member inline this.IsSealed = this.GetTypeInfo().IsSealed member inline this.IsAssignableFrom(otherType: Type) = this.GetTypeInfo().IsAssignableFrom(otherType.GetTypeInfo()) member inline this.GetGenericArguments() = this.GetTypeInfo().GenericTypeArguments - member inline this.GetProperty(name) = this.GetRuntimeProperty(name) - member inline this.GetMethod(name, parameterTypes) = this.GetRuntimeMethod(name, parameterTypes) + member inline this.GetProperty(name) = this.GetTypeInfo().GetProperty(name) + member inline this.GetMethod(name:string, parameterTypes: Type[]) = this.GetTypeInfo().GetMethod(name, parameterTypes) member inline this.GetCustomAttributes(attributeType: Type, inherits: bool) : obj[] = unboxPrim<_> (box (CustomAttributeExtensions.GetCustomAttributes(this.GetTypeInfo(), attributeType, inherits).ToArray())) @@ -414,7 +419,7 @@ namespace Microsoft.FSharp.Core let inline (+..) (x:uint64) (y:uint64) = (# "add" x y : uint64 #) let inline ( *. ) (x:int64) (y:int64) = (# "mul" x y : int64 #) let inline ( *.. ) (x:uint64) (y:uint64) = (# "mul" x y : uint64 #) - let inline (^) (x:string) (y:string) = System.String.Concat(x,y) + let inline (^) (x:string) (y:string) = String.Concat(x,y) let inline (<<<) (x:int) (y:int) = (# "shl" x y : int #) let inline ( * ) (x:int) (y:int) = (# "mul" x y : int #) let inline (-) (x:int) (y:int) = (# "sub" x y : int #) @@ -463,14 +468,14 @@ namespace Microsoft.FSharp.Core let inline iscastPrim<'T when 'T : not struct>(x:obj) = (# "isinst !0" type ('T) x : 'T #) + let inline mask (n:int) (m:int) = (# "and" n m : int #) open BasicInlinedOperations module TupleUtils = - // adapted from System.Tuple :: CombineHashCodes - let inline mask (n:int) (m:int) = (# "and" n m : int #) + // adapted from System.Tuple::CombineHashCodes let inline opshl (x:int) (n:int) : int = (# "shl" x (mask n 31) : int #) let inline opxor (x:int) (y:int) : int = (# "xor" x y : int32 #) let inline combineTupleHashes (h1 : int) (h2 : int) = (opxor ((opshl h1 5) + h1) h2) @@ -595,7 +600,7 @@ namespace Microsoft.FSharp.Core then TypeNullnessSemantics_NullNotLiked else TypeNullnessSemantics_NullTrueValue - [] + type TypeInfo<'T>() = // Compute an on-demand per-instantiation static field static let info = getTypeInfo typeof<'T> @@ -829,7 +834,7 @@ namespace Microsoft.FSharp.Core // Use Ordinal comparison for strings | (:? string as x),(:? string as y) -> - System.String.CompareOrdinal(x, y) + String.CompareOrdinal(x, y) // Permit structural comparison on arrays | (:? System.Array as arr1),_ -> @@ -1103,10 +1108,10 @@ namespace Microsoft.FSharp.Core else GenericComparisonWithComparerIntrinsic comp x y when 'T : char = if (# "clt.un" x y : bool #) then (-1) else (# "cgt.un" x y : int #) when 'T : string = - // NOTE: we don't have to null check here because System.String.CompareOrdinal + // NOTE: we don't have to null check here because String.CompareOrdinal // gives reliable results on null values. - System.String.CompareOrdinal((# "" x : string #),(# "" y : string #)) - when 'T : decimal = System.Decimal.Compare((# "" x:decimal #), (# "" y:decimal #)) + String.CompareOrdinal((# "" x : string #),(# "" y : string #)) + when 'T : decimal = Decimal.Compare((# "" x:decimal #), (# "" y:decimal #)) /// Generic comparison. Implements ER mode (where "0" is returned when NaNs are compared) @@ -1181,10 +1186,10 @@ namespace Microsoft.FSharp.Core else (# "ceq" x x : int #) when 'T : char = if (# "clt.un" x y : bool #) then (-1) else (# "cgt.un" x y : int #) when 'T : string = - // NOTE: we don't have to null check here because System.String.CompareOrdinal + // NOTE: we don't have to null check here because String.CompareOrdinal // gives reliable results on null values. - System.String.CompareOrdinal((# "" x : string #),(# "" y : string #)) - when 'T : decimal = System.Decimal.Compare((# "" x:decimal #), (# "" y:decimal #)) + String.CompareOrdinal((# "" x : string #),(# "" y : string #)) + when 'T : decimal = Decimal.Compare((# "" x:decimal #), (# "" y:decimal #)) /// Generic less-than with static optimizations for some well-known cases. let inline GenericLessThanFast (x:'T) (y:'T) = @@ -1203,7 +1208,7 @@ namespace Microsoft.FSharp.Core when 'T : float = (# "clt" x y : bool #) when 'T : float32= (# "clt" x y : bool #) when 'T : char = (# "clt" x y : bool #) - when 'T : decimal = System.Decimal.op_LessThan ((# "" x:decimal #), (# "" y:decimal #)) + when 'T : decimal = Decimal.op_LessThan ((# "" x:decimal #), (# "" y:decimal #)) /// Generic greater-than with static optimizations for some well-known cases. let inline GenericGreaterThanFast (x:'T) (y:'T) = @@ -1222,7 +1227,7 @@ namespace Microsoft.FSharp.Core when 'T : float = (# "cgt" x y : bool #) when 'T : float32 = (# "cgt" x y : bool #) when 'T : char = (# "cgt" x y : bool #) - when 'T : decimal = System.Decimal.op_GreaterThan ((# "" x:decimal #), (# "" y:decimal #)) + when 'T : decimal = Decimal.op_GreaterThan ((# "" x:decimal #), (# "" y:decimal #)) /// Generic less-than-or-equal with static optimizations for some well-known cases. let inline GenericLessOrEqualFast (x:'T) (y:'T) = @@ -1241,7 +1246,7 @@ namespace Microsoft.FSharp.Core when 'T : float = not (# "cgt.un" x y : bool #) when 'T : float32 = not (# "cgt.un" x y : bool #) when 'T : char = not(# "cgt" x y : bool #) - when 'T : decimal = System.Decimal.op_LessThanOrEqual ((# "" x:decimal #), (# "" y:decimal #)) + when 'T : decimal = Decimal.op_LessThanOrEqual ((# "" x:decimal #), (# "" y:decimal #)) /// Generic greater-than-or-equal with static optimizations for some well-known cases. let inline GenericGreaterOrEqualFast (x:'T) (y:'T) = @@ -1260,7 +1265,7 @@ namespace Microsoft.FSharp.Core when 'T : float = not (# "clt.un" x y : bool #) when 'T : float32 = not (# "clt.un" x y : bool #) when 'T : char = not (# "clt" x y : bool #) - when 'T : decimal = System.Decimal.op_GreaterThanOrEqual ((# "" x:decimal #), (# "" y:decimal #)) + when 'T : decimal = Decimal.op_GreaterThanOrEqual ((# "" x:decimal #), (# "" y:decimal #)) //------------------------------------------------------------------------- @@ -1376,7 +1381,7 @@ namespace Microsoft.FSharp.Core | null,null -> true | null,_ -> false | _,null -> false - | (:? string as xs),(:? string as ys) -> System.String.Equals(xs,ys) + | (:? string as xs),(:? string as ys) -> String.Equals(xs,ys) // Permit structural equality on arrays | (:? System.Array as arr1),_ -> match arr1,yobj with @@ -1601,8 +1606,8 @@ namespace Microsoft.FSharp.Core else not (# "ceq" x x : bool #) && not (# "ceq" y y : bool #) when 'T : char = (# "ceq" x y : bool #) - when 'T : string = System.String.Equals((# "" x : string #),(# "" y : string #)) - when 'T : decimal = System.Decimal.op_Equality((# "" x:decimal #), (# "" y:decimal #)) + when 'T : string = String.Equals((# "" x : string #),(# "" y : string #)) + when 'T : decimal = Decimal.op_Equality((# "" x:decimal #), (# "" y:decimal #)) /// Implements generic equality between two values, with PER semantics for NaN (so equality on two NaN values returns false) // @@ -1623,8 +1628,8 @@ namespace Microsoft.FSharp.Core when 'T : char = (# "ceq" x y : bool #) when 'T : nativeint = (# "ceq" x y : bool #) when 'T : unativeint = (# "ceq" x y : bool #) - when 'T : string = System.String.Equals((# "" x : string #),(# "" y : string #)) - when 'T : decimal = System.Decimal.op_Equality((# "" x:decimal #), (# "" y:decimal #)) + when 'T : string = String.Equals((# "" x : string #),(# "" y : string #)) + when 'T : decimal = Decimal.op_Equality((# "" x:decimal #), (# "" y:decimal #)) /// A compiler intrinsic generated during optimization of calls to GenericEqualityIntrinsic on tuple values. // @@ -1649,8 +1654,8 @@ namespace Microsoft.FSharp.Core when 'T : char = (# "ceq" x y : bool #) when 'T : nativeint = (# "ceq" x y : bool #) when 'T : unativeint = (# "ceq" x y : bool #) - when 'T : string = System.String.Equals((# "" x : string #),(# "" y : string #)) - when 'T : decimal = System.Decimal.op_Equality((# "" x:decimal #), (# "" y:decimal #)) + when 'T : string = String.Equals((# "" x : string #),(# "" y : string #)) + when 'T : decimal = Decimal.op_Equality((# "" x:decimal #), (# "" y:decimal #)) let inline GenericInequalityFast (x:'T) (y:'T) = (not(GenericEqualityFast x y) : bool) @@ -2334,13 +2339,13 @@ namespace Microsoft.FSharp.Core let inline EnumOfValue (value : 'T) : 'Enum when 'Enum : enum<'T> = unboxPrim<'Enum>(box value) // According to the somewhat subtle rules of static optimizations, - // this condition is used whenever 'Enum is resolved to a nominal type + // this condition is used whenever 'Enum is resolved to a nominal type or witnesses are available when 'Enum : 'Enum = (retype value : 'Enum) let inline EnumToValue (enum : 'Enum) : 'T when 'Enum : enum<'T> = unboxPrim<'T>(box enum) // According to the somewhat subtle rules of static optimizations, - // this condition is used whenever 'Enum is resolved to a nominal type + // this condition is used whenever 'Enum is resolved to a nominal type or witnesses are available when 'Enum : 'Enum = (retype enum : 'T) //------------------------------------------------------------------------- @@ -2469,8 +2474,540 @@ namespace Microsoft.FSharp.Core | 'o' -> parseOctalUInt64 s p l | _ -> UInt64.Parse(s.Substring(p), NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture) + let inline ParseByte (s:string) = (# "conv.ovf.u1" (ParseUInt32 s) : byte #) + + let inline ParseSByte (s:string) = (# "conv.ovf.i1" (ParseInt32 s) : sbyte #) + + let inline ParseInt16 (s:string) = (# "conv.ovf.i2" (ParseInt32 s) : int16 #) + + let inline ParseUInt16 (s:string) = (# "conv.ovf.u2" (ParseUInt32 s) : uint16 #) + + let inline ParseIntPtr (s:string) = (# "conv.ovf.i" (ParseInt64 s) : nativeint #) + + let inline ParseUIntPtr (s:string) = (# "conv.ovf.u" (ParseInt64 s) : unativeint #) + + let inline ParseDouble (s:string) = Double.Parse(removeUnderscores s,NumberStyles.Float, CultureInfo.InvariantCulture) + + let inline ParseSingle (s:string) = Single.Parse(removeUnderscores s,NumberStyles.Float, CultureInfo.InvariantCulture) + + type BuiltInWitnesses = +#if BUILDING_WITH_LKG + static member NoUseOfWitnessesAllowedInProto() = () +#else + static member inline op_Addition(x: int32, y: int32) = (# "add" x y : int32 #) + static member inline op_Addition(x: float, y: float) = (# "add" x y : float #) + static member inline op_Addition(x: float32, y: float32) = (# "add" x y : float32 #) + static member inline op_Addition(x: int64, y: int64) = (# "add" x y : int64 #) + static member inline op_Addition(x: uint64, y: uint64) = (# "add" x y : uint64 #) + static member inline op_Addition(x: uint32, y: uint32) = (# "add" x y : uint32 #) + static member inline op_Addition(x: nativeint, y: nativeint) = (# "add" x y : nativeint #) + static member inline op_Addition(x: unativeint, y: unativeint) = (# "add" x y : unativeint #) + static member inline op_Addition(x: int16, y: int16) = (# "conv.i2" (# "add" x y : int32 #) : int16 #) + static member inline op_Addition(x: uint16, y: uint16) = (# "conv.u2" (# "add" x y : uint32 #) : uint16 #) + static member inline op_Addition(x: char, y: char) = (# "conv.u2" (# "add" x y : uint32 #) : char #) + static member inline op_Addition(x: sbyte, y: sbyte) = (# "conv.i1" (# "add" x y : int32 #) : sbyte #) + static member inline op_Addition(x: byte, y: byte) = (# "conv.u1" (# "add" x y : uint32 #) : byte #) + static member inline op_Addition(x: string, y: string) = String.Concat(x, y) + static member inline op_Addition(x: decimal, y: decimal) = Decimal.op_Addition(x, y) + + static member inline op_Multiply(x: int32, y: int32) = (# "mul" x y : int32 #) + static member inline op_Multiply(x: float, y: float) = (# "mul" x y : float #) + static member inline op_Multiply(x: float32, y: float32) = (# "mul" x y : float32 #) + static member inline op_Multiply(x: int64, y: int64) = (# "mul" x y : int64 #) + static member inline op_Multiply(x: uint64, y: uint64) = (# "mul" x y : uint64 #) + static member inline op_Multiply(x: uint32, y: uint32) = (# "mul" x y : uint32 #) + static member inline op_Multiply(x: nativeint, y: nativeint) = (# "mul" x y : nativeint #) + static member inline op_Multiply(x: unativeint, y: unativeint) = (# "mul" x y : unativeint #) + static member inline op_Multiply(x: int16, y: int16) = (# "conv.i2" (# "mul" x y : int32 #) : int16 #) + static member inline op_Multiply(x: uint16, y: uint16) = (# "conv.u2" (# "mul" x y : uint32 #) : uint16 #) + static member inline op_Multiply(x: sbyte, y: sbyte) = (# "conv.i1" (# "mul" x y : int32 #) : sbyte #) + static member inline op_Multiply(x: byte, y: byte) = (# "conv.u1" (# "mul" x y : uint32 #) : byte #) + static member inline op_Multiply(x: decimal, y: decimal) = Decimal.op_Multiply(x, y) + + static member inline op_UnaryNegation(value: int32) = (# "neg" value : int32 #) + static member inline op_UnaryNegation(value: float) = (# "neg" value : float #) + static member inline op_UnaryNegation(value: float32) = (# "neg" value : float32 #) + static member inline op_UnaryNegation(value: int64) = (# "neg" value : int64 #) + static member inline op_UnaryNegation(value: int16) = (# "neg" value : int16 #) + static member inline op_UnaryNegation(value: nativeint) = (# "neg" value : nativeint #) + static member inline op_UnaryNegation(value: sbyte) = (# "neg" value : sbyte #) + static member inline op_UnaryNegation(value: decimal) = Decimal.op_UnaryNegation(value) + + static member inline op_Subtraction(x: int32, y: int32) = (# "sub" x y : int32 #) + static member inline op_Subtraction(x: float, y: float) = (# "sub" x y : float #) + static member inline op_Subtraction(x: float32, y: float32) = (# "sub" x y : float32 #) + static member inline op_Subtraction(x: int64, y: int64) = (# "sub" x y : int64 #) + static member inline op_Subtraction(x: uint64, y: uint64) = (# "sub" x y : uint64 #) + static member inline op_Subtraction(x: uint32, y: uint32) = (# "sub" x y : uint32 #) + static member inline op_Subtraction(x: nativeint, y: nativeint) = (# "sub" x y : nativeint #) + static member inline op_Subtraction(x: unativeint, y: unativeint) = (# "sub" x y : unativeint #) + static member inline op_Subtraction(x: int16, y: int16) = (# "conv.i2" (# "sub" x y : int32 #) : int16 #) + static member inline op_Subtraction(x: uint16, y: uint16) = (# "conv.u2" (# "sub" x y : uint32 #) : uint16 #) + static member inline op_Subtraction(x: sbyte, y: sbyte) = (# "conv.i1" (# "sub" x y : int32 #) : sbyte #) + static member inline op_Subtraction(x: byte, y: byte) = (# "conv.u1" (# "sub" x y : uint32 #) : byte #) + static member inline op_Subtraction(x: decimal, y: decimal) = Decimal.op_Subtraction(x, y) + + static member inline op_Division(x: int32, y: int32) = (# "div" x y : int32 #) + static member inline op_Division(x: float, y: float) = (# "div" x y : float #) + static member inline op_Division(x: float32, y: float32) = (# "div" x y : float32 #) + static member inline op_Division(x: int64, y: int64) = (# "div" x y : int64 #) + static member inline op_Division(x: uint64, y: uint64) = (# "div.un" x y : uint64 #) + static member inline op_Division(x: uint32, y: uint32) = (# "div.un" x y : uint32 #) + static member inline op_Division(x: nativeint, y: nativeint) = (# "div" x y : nativeint #) + static member inline op_Division(x: unativeint, y: unativeint) = (# "div.un" x y : unativeint #) + static member inline op_Division(x: int16, y: int16) = (# "conv.i2" (# "div" x y : int32 #) : int16 #) + static member inline op_Division(x: uint16, y: uint16) = (# "conv.u2" (# "div.un" x y : uint32 #) : uint16 #) + static member inline op_Division(x: sbyte, y: sbyte) = (# "conv.i1" (# "div" x y : int32 #) : sbyte #) + static member inline op_Division(x: byte, y: byte) = (# "conv.u1" (# "div.un" x y : uint32 #) : byte #) + static member inline op_Division(x: decimal, y: decimal) = Decimal.op_Division(x, y) + + static member inline op_Modulus(x: int32, y: int32) = (# "rem" x y : int32 #) + static member inline op_Modulus(x: float, y: float) = (# "rem" x y : float #) + static member inline op_Modulus(x: float32, y: float32) = (# "rem" x y : float32 #) + static member inline op_Modulus(x: int64, y: int64) = (# "rem" x y : int64 #) + static member inline op_Modulus(x: uint64, y: uint64) = (# "rem.un" x y : uint64 #) + static member inline op_Modulus(x: uint32, y: uint32) = (# "rem.un" x y : uint32 #) + static member inline op_Modulus(x: nativeint, y: nativeint) = (# "rem" x y : nativeint #) + static member inline op_Modulus(x: unativeint, y: unativeint) = (# "rem.un" x y : unativeint #) + static member inline op_Modulus(x: int16, y: int16) = (# "conv.i2" (# "rem" x y : int32 #) : int16 #) + static member inline op_Modulus(x: uint16, y: uint16) = (# "conv.u2" (# "rem.un" x y : uint32 #) : uint16 #) + static member inline op_Modulus(x: sbyte, y: sbyte) = (# "conv.i1" (# "rem" x y : int32 #) : sbyte #) + static member inline op_Modulus(x: byte, y: byte) = (# "conv.u1" (# "rem.un" x y : uint32 #) : byte #) + static member inline op_Modulus(x: decimal, y: decimal) = Decimal.op_Modulus(x, y) + + static member inline op_CheckedAddition(x: int32, y: int32) = (# "add.ovf" x y : int32 #) + static member inline op_CheckedAddition(x: float, y: float) = (# "add" x y : float #) + static member inline op_CheckedAddition(x: float32, y: float32) = (# "add" x y : float32 #) + static member inline op_CheckedAddition(x: int64, y: int64) = (# "add.ovf" x y : int64 #) + static member inline op_CheckedAddition(x: uint64, y: uint64) = (# "add.ovf.un" x y : uint64 #) + static member inline op_CheckedAddition(x: uint32, y: uint32) = (# "add.ovf.un" x y : uint32 #) + static member inline op_CheckedAddition(x: nativeint, y: nativeint) = (# "add.ovf" x y : nativeint #) + static member inline op_CheckedAddition(x: unativeint, y: unativeint) = (# "add.ovf.un" x y : unativeint #) + static member inline op_CheckedAddition(x: int16, y: int16) = (# "conv.ovf.i2" (# "add.ovf" x y : int32 #) : int16 #) + static member inline op_CheckedAddition(x: uint16, y: uint16) = (# "conv.ovf.u2.un" (# "add.ovf.un" x y : uint32 #) : uint16 #) + static member inline op_CheckedAddition(x: char, y: char) = (# "conv.ovf.u2.un" (# "add.ovf.un" x y : uint32 #) : char #) + static member inline op_CheckedAddition(x: sbyte, y: sbyte) = (# "conv.ovf.i1" (# "add.ovf" x y : int32 #) : sbyte #) + static member inline op_CheckedAddition(x: byte, y: byte) = (# "conv.ovf.u1.un" (# "add.ovf.un" x y : uint32 #) : byte #) + static member inline op_CheckedAddition(x: string, y: string) = String.Concat(x, y) + + static member inline op_CheckedSubtraction(x: int32, y: int32) = (# "sub.ovf" x y : int32 #) + static member inline op_CheckedSubtraction(x: float, y: float) = (# "sub" x y : float #) + static member inline op_CheckedSubtraction(x: float32, y: float32) = (# "sub" x y : float32 #) + static member inline op_CheckedSubtraction(x: int64, y: int64) = (# "sub.ovf" x y : int64 #) + static member inline op_CheckedSubtraction(x: uint64, y: uint64) = (# "sub.ovf.un" x y : uint64 #) + static member inline op_CheckedSubtraction(x: uint32, y: uint32) = (# "sub.ovf.un" x y : uint32 #) + static member inline op_CheckedSubtraction(x: nativeint, y: nativeint) = (# "sub.ovf" x y : nativeint #) + static member inline op_CheckedSubtraction(x: unativeint, y: unativeint) = (# "sub.ovf.un" x y : unativeint #) + static member inline op_CheckedSubtraction(x: int16, y: int16) = (# "conv.ovf.i2" (# "sub.ovf" x y : int32 #) : int16 #) + static member inline op_CheckedSubtraction(x: uint16, y: uint16) = (# "conv.ovf.u2.un" (# "sub.ovf.un" x y : uint32 #) : uint16 #) + static member inline op_CheckedSubtraction(x: sbyte, y: sbyte) = (# "conv.ovf.i1" (# "sub.ovf" x y : int32 #) : sbyte #) + static member inline op_CheckedSubtraction(x: byte, y: byte) = (# "conv.ovf.u1.un" (# "sub.ovf.un" x y : uint32 #) : byte #) + + static member inline op_CheckedMultiply(x: int32, y: int32) = (# "mul.ovf" x y : int32 #) + static member inline op_CheckedMultiply(x: float, y: float) = (# "mul" x y : float #) + static member inline op_CheckedMultiply(x: float32, y: float32) = (# "mul" x y : float32 #) + static member inline op_CheckedMultiply(x: int64, y: int64) = (# "mul.ovf" x y : int64 #) + static member inline op_CheckedMultiply(x: uint64, y: uint64) = (# "mul.ovf.un" x y : uint64 #) + static member inline op_CheckedMultiply(x: uint32, y: uint32) = (# "mul.ovf.un" x y : uint32 #) + static member inline op_CheckedMultiply(x: nativeint, y: nativeint) = (# "mul.ovf" x y : nativeint #) + static member inline op_CheckedMultiply(x: unativeint, y: unativeint) = (# "mul.ovf.un" x y : unativeint #) + static member inline op_CheckedMultiply(x: int16, y: int16) = (# "conv.ovf.i2" (# "mul.ovf" x y : int32 #) : int16 #) + static member inline op_CheckedMultiply(x: uint16, y: uint16) = (# "conv.ovf.u2.un" (# "mul.ovf.un" x y : uint16 #) : uint16 #) + static member inline op_CheckedMultiply(x: sbyte, y: sbyte) = (# "conv.ovf.i1" (# "mul.ovf" x y : int32 #) : sbyte #) + static member inline op_CheckedMultiply(x: byte, y: byte) = (# "conv.ovf.u1.un" (# "mul.ovf.un" x y : uint32 #) : byte #) + + static member inline op_CheckedUnaryNegation(value: int32) = (# "sub.ovf" 0 value : int32 #) + static member inline op_CheckedUnaryNegation(value: float) = (# "neg" value : float #) + static member inline op_CheckedUnaryNegation(value: float32) = (# "neg" value : float32 #) + static member inline op_CheckedUnaryNegation(value: int64) = (# "sub.ovf" 0L value : int64 #) + static member inline op_CheckedUnaryNegation(value: int16) = (# "sub.ovf" 0s value : int16 #) + static member inline op_CheckedUnaryNegation(value: nativeint) = (# "sub.ovf" 0n value : nativeint #) + static member inline op_CheckedUnaryNegation(value: sbyte) = (# "sub.ovf" 0y value : sbyte #) + + static member inline op_LeftShift(value: int32, shift: int32) = (# "shl" value (mask shift 31) : int #) + static member inline op_LeftShift(value: uint32, shift: int32) = (# "shl" value (mask shift 31) : uint32 #) + static member inline op_LeftShift(value: int64, shift: int32) = (# "shl" value (mask shift 63) : int64 #) + static member inline op_LeftShift(value: uint64, shift: int32) = (# "shl" value (mask shift 63) : uint64 #) + static member inline op_LeftShift(value: nativeint, shift: int32) = (# "shl" value shift : nativeint #) + static member inline op_LeftShift(value: unativeint, shift: int32) = (# "shl" value shift : unativeint #) + static member inline op_LeftShift(value: int16, shift: int32) = (# "conv.i2" (# "shl" value (mask shift 15) : int32 #) : int16 #) + static member inline op_LeftShift(value: uint16, shift: int32) = (# "conv.u2" (# "shl" value (mask shift 15) : uint32 #) : uint16 #) + static member inline op_LeftShift(value: sbyte, shift: int32) = (# "conv.i1" (# "shl" value (mask shift 7) : int32 #) : sbyte #) + static member inline op_LeftShift(value: byte, shift: int32) = (# "conv.u1" (# "shl" value (mask shift 7) : uint32 #) : byte #) + + static member inline op_RightShift(value: sbyte, shift: int32) = (# "conv.i1" (# "shr" value (mask shift 7 ) : int32 #) : sbyte #) + static member inline op_RightShift(value: byte, shift: int32) = (# "conv.u1" (# "shr.un" value (mask shift 7 ) : uint32 #) : byte #) + static member inline op_RightShift(value: int16, shift: int32) = (# "conv.i2" (# "shr" value (mask shift 15) : int32 #) : int16 #) + static member inline op_RightShift(value: uint16, shift: int32) = (# "conv.u2" (# "shr.un" value (mask shift 15) : uint32 #) : uint16 #) + static member inline op_RightShift(value: int32, shift: int32) = (# "shr" value (mask shift 31) : int32 #) + static member inline op_RightShift(value: uint32, shift: int32) = (# "shr.un" value (mask shift 31) : uint32 #) + static member inline op_RightShift(value: int64, shift: int32) = (# "shr" value (mask shift 63) : int64 #) + static member inline op_RightShift(value: uint64, shift: int32) = (# "shr.un" value (mask shift 63) : uint64 #) + static member inline op_RightShift(value: nativeint, shift: int32) = (# "shr" value shift : nativeint #) + static member inline op_RightShift(value: unativeint, shift: int32) = (# "shr.un" value shift : unativeint #) + + static member inline op_BitwiseAnd(x: sbyte, y: sbyte) = (# "and" x y : sbyte #) + static member inline op_BitwiseAnd(x: byte, y: byte) = (# "and" x y : byte #) + static member inline op_BitwiseAnd(x: int16, y: int16) = (# "and" x y : int16 #) + static member inline op_BitwiseAnd(x: uint16, y: uint16) = (# "and" x y : uint16 #) + static member inline op_BitwiseAnd(x: int32, y: int32) = (# "and" x y : int32 #) + static member inline op_BitwiseAnd(x: uint32, y: uint32) = (# "and" x y : uint32 #) + static member inline op_BitwiseAnd(x: int64, y: int64) = (# "and" x y : int64 #) + static member inline op_BitwiseAnd(x: uint64, y: uint64) = (# "and" x y : uint64 #) + static member inline op_BitwiseAnd(x: nativeint, y: nativeint) = (# "and" x y : nativeint #) + static member inline op_BitwiseAnd(x: unativeint, y: unativeint) = (# "and" x y : unativeint #) + + static member inline op_BitwiseOr(x: sbyte, y: sbyte) = (# "or" x y : sbyte #) + static member inline op_BitwiseOr(x: byte, y: byte) = (# "or" x y : byte #) + static member inline op_BitwiseOr(x: int16, y: int16) = (# "or" x y : int16 #) + static member inline op_BitwiseOr(x: uint16, y: uint16) = (# "or" x y : uint16 #) + static member inline op_BitwiseOr(x: int32, y: int32) = (# "or" x y : int32 #) + static member inline op_BitwiseOr(x: uint32, y: uint32) = (# "or" x y : uint32 #) + static member inline op_BitwiseOr(x: int64, y: int64) = (# "or" x y : int64 #) + static member inline op_BitwiseOr(x: uint64, y: uint64) = (# "or" x y : uint64 #) + static member inline op_BitwiseOr(x: nativeint, y: nativeint) = (# "or" x y : nativeint #) + static member inline op_BitwiseOr(x: unativeint, y: unativeint) = (# "or" x y : unativeint #) + + static member inline op_ExclusiveOr(x: sbyte, y: sbyte) = (# "xor" x y : sbyte #) + static member inline op_ExclusiveOr(x: byte, y: byte) = (# "xor" x y : byte #) + static member inline op_ExclusiveOr(x: int16, y: int16) = (# "xor" x y : int16 #) + static member inline op_ExclusiveOr(x: uint16, y: uint16) = (# "xor" x y : uint16 #) + static member inline op_ExclusiveOr(x: int32, y: int32) = (# "xor" x y : int32 #) + static member inline op_ExclusiveOr(x: uint32, y: uint32) = (# "xor" x y : uint32 #) + static member inline op_ExclusiveOr(x: int64, y: int64) = (# "xor" x y : int64 #) + static member inline op_ExclusiveOr(x: uint64, y: uint64) = (# "xor" x y : uint64 #) + static member inline op_ExclusiveOr(x: nativeint, y: nativeint) = (# "xor" x y : nativeint #) + static member inline op_ExclusiveOr(x: unativeint, y: unativeint) = (# "xor" x y : unativeint #) + + static member inline op_LogicalNot(value: sbyte) = (# "conv.i1" (# "not" value : int32 #) : sbyte #) + static member inline op_LogicalNot(value: byte) = (# "conv.u1" (# "not" value : uint32 #) : byte #) + static member inline op_LogicalNot(value: int16) = (# "conv.i2" (# "not" value : int32 #) : int16 #) + static member inline op_LogicalNot(value: uint16) = (# "conv.u2" (# "not" value : uint32 #) : uint16 #) + static member inline op_LogicalNot(value: int32) = (# "not" value : int32 #) + static member inline op_LogicalNot(value: uint32) = (# "not" value : uint32 #) + static member inline op_LogicalNot(value: int64) = (# "not" value : int64 #) + static member inline op_LogicalNot(value: uint64) = (# "not" value : uint64 #) + static member inline op_LogicalNot(value: nativeint) = (# "not" value : nativeint #) + static member inline op_LogicalNot(value: unativeint) = (# "not" value : unativeint #) + + static member inline op_Explicit(value: sbyte) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: byte) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: int16) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: uint16) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: int32) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: uint32) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: int64) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: uint64) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: nativeint) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: unativeint) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: float) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: float32) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: char) : byte = (# "conv.u1" value : byte #) + static member inline op_Explicit(value: string) : byte = ParseByte value + + static member inline op_Explicit(value: string) : sbyte = ParseSByte value + static member inline op_Explicit(value: float) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: float32) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: int64) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: int32) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: int16) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: nativeint) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: sbyte) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: uint64) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: uint32) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: uint16) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: char) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: unativeint) : sbyte = (# "conv.i1" value : sbyte #) + static member inline op_Explicit(value: byte) : sbyte = (# "conv.i1" value : sbyte #) + + static member inline op_Explicit(value: string) : uint16 = ParseUInt16 value + static member inline op_Explicit(value: float) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: float32) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: int64) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: int32) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: int16) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: nativeint) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: sbyte) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: uint64) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: uint32) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: uint16) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: char) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: unativeint) : uint16 = (# "conv.u2" value : uint16 #) + static member inline op_Explicit(value: byte) : uint16 = (# "conv.u2" value : uint16 #) + + static member inline op_Explicit(value: string) : int16 = ParseInt16 value + static member inline op_Explicit(value: float) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: float32) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: int64) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: int32) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: int16) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: nativeint) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: sbyte) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: uint64) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: uint32) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: uint16) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: char) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: unativeint) : int16 = (# "conv.i2" value : int16 #) + static member inline op_Explicit(value: byte) : int16 = (# "conv.i2" value : int16 #) + + static member inline op_Explicit(value: string) : uint32 = ParseUInt32 value + static member inline op_Explicit(value: float) : uint32 = (# "conv.u4" value : uint32 #) + static member inline op_Explicit(value: float32) : uint32 = (# "conv.u4" value : uint32 #) + static member inline op_Explicit(value: int64) : uint32 = (# "conv.u4" value : uint32 #) + static member inline op_Explicit(value: nativeint) : uint32 = (# "conv.u4" value : uint32 #) + static member inline op_Explicit(value: int32) : uint32 = (# "" value : uint32 #) + static member inline op_Explicit(value: int16) : uint32 = (# "" value : uint32 #) + static member inline op_Explicit(value: sbyte) : uint32 = (# "" value : uint32 #) + static member inline op_Explicit(value: uint64) : uint32 = (# "conv.u4" value : uint32 #) + static member inline op_Explicit(value: uint32) : uint32 = (# "conv.u4" value : uint32 #) + static member inline op_Explicit(value: uint16) : uint32 = (# "conv.u4" value : uint32 #) + static member inline op_Explicit(value: char) : uint32 = (# "conv.u4" value : uint32 #) + static member inline op_Explicit(value: unativeint) : uint32 = (# "conv.u4" value : uint32 #) + static member inline op_Explicit(value: byte) : uint32 = (# "conv.u4" value : uint32 #) + + static member inline op_Explicit(value: string) : int32 = ParseInt32 value + static member inline op_Explicit(value: float) : int32 = (# "conv.i4" value : int32 #) + static member inline op_Explicit(value: float32) : int32 = (# "conv.i4" value : int32 #) + static member inline op_Explicit(value: int64) : int32 = (# "conv.i4" value : int32 #) + static member inline op_Explicit(value: nativeint) : int32 = (# "conv.i4" value : int32 #) + static member inline op_Explicit(value: int32) : int32 = (# "" value : int32 #) + static member inline op_Explicit(value: int16) : int32 = (# "" value : int32 #) + static member inline op_Explicit(value: sbyte) : int32 = (# "" value : int32 #) + static member inline op_Explicit(value: uint64) : int32 = (# "conv.i4" value : int32 #) + static member inline op_Explicit(value: uint32) : int32 = (# "" value : int32 #) + static member inline op_Explicit(value: uint16) : int32 = (# "conv.i4" value : int32 #) + static member inline op_Explicit(value: char) : int32 = (# "conv.i4" value : int32 #) + static member inline op_Explicit(value: unativeint) : int32 = (# "conv.i4" value : int32 #) + static member inline op_Explicit(value: byte) : int32 = (# "conv.i4" value : int32 #) + + static member inline op_Explicit(value: string) : uint64 = ParseUInt64 value + static member inline op_Explicit(value: float) : uint64 = (# "conv.u8" value : uint64 #) + static member inline op_Explicit(value: float32) : uint64 = (# "conv.u8" value : uint64 #) + static member inline op_Explicit(value: int64) : uint64 = (# "" value : uint64 #) + static member inline op_Explicit(value: int32) : uint64 = (# "conv.i8" value : uint64 #) + static member inline op_Explicit(value: int16) : uint64 = (# "conv.i8" value : uint64 #) + static member inline op_Explicit(value: nativeint) : uint64 = (# "conv.i8" value : uint64 #) + static member inline op_Explicit(value: sbyte) : uint64 = (# "conv.i8" value : uint64 #) + static member inline op_Explicit(value: uint64) : uint64 = (# "" value : uint64 #) + static member inline op_Explicit(value: uint32) : uint64 = (# "conv.u8" value : uint64 #) + static member inline op_Explicit(value: uint16) : uint64 = (# "conv.u8" value : uint64 #) + static member inline op_Explicit(value: char) : uint64 = (# "conv.u8" value : uint64 #) + static member inline op_Explicit(value: unativeint) : uint64 = (# "conv.u8" value : uint64 #) + static member inline op_Explicit(value: byte) : uint64 = (# "conv.u8" value : uint64 #) + + static member inline op_Explicit(value: string) : int64 = ParseInt64 value + static member inline op_Explicit(value: float) : int64 = (# "conv.i8" value : int64 #) + static member inline op_Explicit(value: float32) : int64 = (# "conv.i8" value : int64 #) + static member inline op_Explicit(value: int64) : int64 = (# "conv.i8" value : int64 #) + static member inline op_Explicit(value: int32) : int64 = (# "conv.i8" value : int64 #) + static member inline op_Explicit(value: int16) : int64 = (# "conv.i8" value : int64 #) + static member inline op_Explicit(value: nativeint) : int64 = (# "conv.i8" value : int64 #) + static member inline op_Explicit(value: sbyte) : int64 = (# "conv.i8" value : int64 #) + static member inline op_Explicit(value: uint64) : int64 = (# "" value : int64 #) + static member inline op_Explicit(value: uint32) : int64 = (# "conv.u8" value : int64 #) + static member inline op_Explicit(value: uint16) : int64 = (# "conv.u8" value : int64 #) + static member inline op_Explicit(value: char) : int64 = (# "conv.u8" value : int64 #) + static member inline op_Explicit(value: unativeint) : int64 = (# "conv.u8" value : int64 #) + static member inline op_Explicit(value: byte) : int64 = (# "conv.u8" value : int64 #) + + static member inline op_Explicit(value: string) : float32 = ParseSingle value + static member inline op_Explicit(value: float) : float32 = (# "conv.r4" value : float32 #) + static member inline op_Explicit(value: float32) : float32 = (# "conv.r4" value : float32 #) + static member inline op_Explicit(value: int64) : float32 = (# "conv.r4" value : float32 #) + static member inline op_Explicit(value: int32) : float32 = (# "conv.r4" value : float32 #) + static member inline op_Explicit(value: int16) : float32 = (# "conv.r4" value : float32 #) + static member inline op_Explicit(value: nativeint) : float32 = (# "conv.r4" value : float32 #) + static member inline op_Explicit(value: sbyte) : float32 = (# "conv.r4" value : float32 #) + static member inline op_Explicit(value: uint64) : float32 = (# "conv.r.un conv.r4" value : float32 #) + static member inline op_Explicit(value: uint32) : float32 = (# "conv.r.un conv.r4" value : float32 #) + static member inline op_Explicit(value: uint16) : float32 = (# "conv.r.un conv.r4" value : float32 #) + static member inline op_Explicit(value: char) : float32 = (# "conv.r.un conv.r4" value : float32 #) + static member inline op_Explicit(value: unativeint) : float32 = (# "conv.r.un conv.r4" value : float32 #) + static member inline op_Explicit(value: byte) : float32 = (# "conv.r.un conv.r4" value : float32 #) + + static member inline op_Explicit(value: string) : float = ParseDouble value + static member inline op_Explicit(value: float) : float = (# "conv.r8" value : float #) + static member inline op_Explicit(value: float32) : float = (# "conv.r8" value : float #) + static member inline op_Explicit(value: int64) : float = (# "conv.r8" value : float #) + static member inline op_Explicit(value: int32) : float = (# "conv.r8" value : float #) + static member inline op_Explicit(value: int16) : float = (# "conv.r8" value : float #) + static member inline op_Explicit(value: nativeint) : float = (# "conv.r8" value : float #) + static member inline op_Explicit(value: sbyte) : float = (# "conv.r8" value : float #) + static member inline op_Explicit(value: uint64) : float = (# "conv.r.un conv.r8" value : float #) + static member inline op_Explicit(value: uint32) : float = (# "conv.r.un conv.r8" value : float #) + static member inline op_Explicit(value: uint16) : float = (# "conv.r.un conv.r8" value : float #) + static member inline op_Explicit(value: char) : float = (# "conv.r.un conv.r8" value : float #) + static member inline op_Explicit(value: unativeint) : float = (# "conv.r.un conv.r8" value : float #) + static member inline op_Explicit(value: byte) : float = (# "conv.r.un conv.r8" value : float #) + static member inline op_Explicit(value: decimal) : float = Convert.ToDouble(value) + + static member inline op_Explicit(value: string) : decimal = Decimal.Parse(value,NumberStyles.Float,CultureInfo.InvariantCulture) + static member inline op_Explicit(value: float) : decimal = Convert.ToDecimal(value) + static member inline op_Explicit(value: float32) : decimal = Convert.ToDecimal(value) + static member inline op_Explicit(value: int64) : decimal = Convert.ToDecimal(value) + static member inline op_Explicit(value: int32) : decimal = Convert.ToDecimal(value) + static member inline op_Explicit(value: int16) : decimal = Convert.ToDecimal(value) + static member inline op_Explicit(value: nativeint) : decimal = Convert.ToDecimal(BuiltInWitnesses.op_Explicit value : int64) + static member inline op_Explicit(value: sbyte) : decimal = Convert.ToDecimal(value) + static member inline op_Explicit(value: uint64) : decimal = Convert.ToDecimal(value) + static member inline op_Explicit(value: uint32) : decimal = Convert.ToDecimal(value) + static member inline op_Explicit(value: uint16) : decimal = Convert.ToDecimal(value) + static member inline op_Explicit(value: unativeint) : decimal = Convert.ToDecimal(BuiltInWitnesses.op_Explicit value : uint64) + static member inline op_Explicit(value: byte) : decimal = Convert.ToDecimal(value) + static member inline op_Explicit(value: decimal) : decimal = value + + static member inline op_Explicit(value: string) : unativeint = ParseUIntPtr value + static member inline op_Explicit(value: float) : unativeint = (# "conv.u" value : unativeint #) + static member inline op_Explicit(value: float32) : unativeint = (# "conv.u" value : unativeint #) + static member inline op_Explicit(value: int64) : unativeint = (# "conv.i" value : unativeint #) + static member inline op_Explicit(value: int32) : unativeint = (# "conv.i" value : unativeint #) + static member inline op_Explicit(value: int16) : unativeint = (# "conv.i" value : unativeint #) + static member inline op_Explicit(value: nativeint) : unativeint = (# "" value : unativeint #) + static member inline op_Explicit(value: sbyte) : unativeint = (# "conv.i" value : unativeint #) + static member inline op_Explicit(value: uint64) : unativeint = (# "conv.u" value : unativeint #) + static member inline op_Explicit(value: uint32) : unativeint = (# "conv.u" value : unativeint #) + static member inline op_Explicit(value: uint16) : unativeint = (# "conv.u" value : unativeint #) + static member inline op_Explicit(value: char) : unativeint = (# "conv.u" value : unativeint #) + static member inline op_Explicit(value: unativeint) : unativeint = (# "" value : unativeint #) + static member inline op_Explicit(value: byte) : unativeint = (# "conv.u" value : unativeint #) + + static member inline op_Explicit(value: string) : nativeint = ParseIntPtr value + static member inline op_Explicit(value: float) : nativeint = (# "conv.i" value : nativeint #) + static member inline op_Explicit(value: float32) : nativeint = (# "conv.i" value : nativeint #) + static member inline op_Explicit(value: int64) : nativeint = (# "conv.i" value : nativeint #) + static member inline op_Explicit(value: int32) : nativeint = (# "conv.i" value : nativeint #) + static member inline op_Explicit(value: int16) : nativeint = (# "conv.i" value : nativeint #) + static member inline op_Explicit(value: nativeint) : nativeint = (# "conv.i" value : nativeint #) + static member inline op_Explicit(value: sbyte) : nativeint = (# "conv.i" value : nativeint #) + static member inline op_Explicit(value: uint64) : nativeint = (# "conv.u" value : nativeint #) + static member inline op_Explicit(value: uint32) : nativeint = (# "conv.u" value : nativeint #) + static member inline op_Explicit(value: uint16) : nativeint = (# "conv.u" value : nativeint #) + static member inline op_Explicit(value: char) : nativeint = (# "conv.u" value : nativeint #) + static member inline op_Explicit(value: unativeint) : nativeint = (# "" value : nativeint #) + static member inline op_Explicit(value: byte) : nativeint = (# "conv.i" value : nativeint #) + + static member inline op_Explicit(value: string) : char = (System.Char.Parse value) + static member inline op_Explicit(value: float) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: float32) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: int64) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: int32) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: int16) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: nativeint) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: sbyte) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: uint64) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: uint32) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: uint16) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: char) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: unativeint) : char = (# "conv.u2" value : char #) + static member inline op_Explicit(value: byte) : char = (# "conv.u2" value : char #) + + static member inline op_LessThan(x: bool, y: bool) = (# "clt" x y : bool #) + static member inline op_LessThan(x: sbyte, y: sbyte) = (# "clt" x y : bool #) + static member inline op_LessThan(x: int16, y: int16) = (# "clt" x y : bool #) + static member inline op_LessThan(x: int32, y: int32) = (# "clt" x y : bool #) + static member inline op_LessThan(x: int64, y: int64) = (# "clt" x y : bool #) + static member inline op_LessThan(x: byte, y: byte) = (# "clt.un" x y : bool #) + static member inline op_LessThan(x: uint16, y: uint16) = (# "clt.un" x y : bool #) + static member inline op_LessThan(x: uint32, y: uint32) = (# "clt.un" x y : bool #) + static member inline op_LessThan(x: uint64, y: uint64) = (# "clt.un" x y : bool #) + static member inline op_LessThan(x: unativeint, y: unativeint) = (# "clt.un" x y : bool #) + static member inline op_LessThan(x: nativeint, y: nativeint) = (# "clt" x y : bool #) + static member inline op_LessThan(x: float, y: float) = (# "clt" x y : bool #) + static member inline op_LessThan(x: float32, y: float32) = (# "clt" x y : bool #) + static member inline op_LessThan(x: char, y: char) = (# "clt" x y : bool #) + static member inline op_LessThan(x: decimal, y: decimal) = Decimal.op_LessThan (x, y) + static member inline op_LessThan(x: string, y: string) = (# "clt" (String.CompareOrdinal(x,y)) 0 : bool #) + + static member inline op_GreaterThan(x: bool, y: bool) = (# "cgt" x y : bool #) + static member inline op_GreaterThan(x: sbyte, y: sbyte) = (# "cgt" x y : bool #) + static member inline op_GreaterThan(x: int16, y: int16) = (# "cgt" x y : bool #) + static member inline op_GreaterThan(x: int32, y: int32) = (# "cgt" x y : bool #) + static member inline op_GreaterThan(x: int64, y: int64) = (# "cgt" x y : bool #) + static member inline op_GreaterThan(x: nativeint, y: nativeint) = (# "cgt" x y : bool #) + static member inline op_GreaterThan(x: byte, y: byte) = (# "cgt.un" x y : bool #) + static member inline op_GreaterThan(x: uint16, y: uint16) = (# "cgt.un" x y : bool #) + static member inline op_GreaterThan(x: uint32, y: uint32) = (# "cgt.un" x y : bool #) + static member inline op_GreaterThan(x: uint64, y: uint64) = (# "cgt.un" x y : bool #) + static member inline op_GreaterThan(x: unativeint, y: unativeint) = (# "cgt.un" x y : bool #) + static member inline op_GreaterThan(x: float, y: float) = (# "cgt" x y : bool #) + static member inline op_GreaterThan(x: float32, y: float32) = (# "cgt" x y : bool #) + static member inline op_GreaterThan(x: char, y: char) = (# "cgt" x y : bool #) + static member inline op_GreaterThan(x: decimal, y: decimal) = Decimal.op_GreaterThan (x, y) + static member inline op_GreaterThan(x: string, y: string) = (# "cgt" (String.CompareOrdinal(x, y)) 0 : bool #) + + static member inline op_LessThanOrEqual(x: bool, y: bool) = not (# "cgt" x y : bool #) + static member inline op_LessThanOrEqual(x: sbyte, y: sbyte) = not (# "cgt" x y : bool #) + static member inline op_LessThanOrEqual(x: int16, y: int16) = not (# "cgt" x y : bool #) + static member inline op_LessThanOrEqual(x: int32, y: int32) = not (# "cgt" x y : bool #) + static member inline op_LessThanOrEqual(x: int64, y: int64) = not (# "cgt" x y : bool #) + static member inline op_LessThanOrEqual(x: nativeint, y: nativeint) = not (# "cgt" x y : bool #) + static member inline op_LessThanOrEqual(x: byte, y: byte) = not (# "cgt.un" x y : bool #) + static member inline op_LessThanOrEqual(x: uint16, y: uint16) = not (# "cgt.un" x y : bool #) + static member inline op_LessThanOrEqual(x: uint32, y: uint32) = not (# "cgt.un" x y : bool #) + static member inline op_LessThanOrEqual(x: uint64, y: uint64) = not (# "cgt.un" x y : bool #) + static member inline op_LessThanOrEqual(x: unativeint, y: unativeint) = not (# "cgt.un" x y : bool #) + static member inline op_LessThanOrEqual(x: float, y: float) = not (# "cgt.un" x y : bool #) + static member inline op_LessThanOrEqual(x: float32, y: float32) = not (# "cgt.un" x y : bool #) + static member inline op_LessThanOrEqual(x: char, y: char) = not (# "cgt" x y : bool #) + static member inline op_LessThanOrEqual(x: decimal, y: decimal) = Decimal.op_LessThanOrEqual (x, y) + static member inline op_LessThanOrEqual(x: string, y: string) = not (# "cgt" (String.CompareOrdinal(x, y)) 0 : bool #) + + static member inline op_GreaterThanOrEqual(x: bool, y: bool) = not (# "clt" x y : bool #) + static member inline op_GreaterThanOrEqual(x: sbyte, y: sbyte) = not (# "clt" x y : bool #) + static member inline op_GreaterThanOrEqual(x: int16, y: int16) = not (# "clt" x y : bool #) + static member inline op_GreaterThanOrEqual(x: int32, y: int32) = not (# "clt" x y : bool #) + static member inline op_GreaterThanOrEqual(x: int64, y: int64) = not (# "clt" x y : bool #) + static member inline op_GreaterThanOrEqual(x: nativeint, y: nativeint) = not (# "clt" x y : bool #) + static member inline op_GreaterThanOrEqual(x: byte, y: byte) = not (# "clt.un" x y : bool #) + static member inline op_GreaterThanOrEqual(x: uint16, y: uint16) = not (# "clt.un" x y : bool #) + static member inline op_GreaterThanOrEqual(x: uint32, y: uint32) = not (# "clt.un" x y : bool #) + static member inline op_GreaterThanOrEqual(x: uint64, y: uint64) = not (# "clt.un" x y : bool #) + static member inline op_GreaterThanOrEqual(x: unativeint, y: unativeint) = not (# "clt.un" x y : bool #) + static member inline op_GreaterThanOrEqual(x: float, y: float) = not (# "clt.un" x y : bool #) + static member inline op_GreaterThanOrEqual(x: float32, y: float32) = not (# "clt.un" x y : bool #) + static member inline op_GreaterThanOrEqual(x: char, y: char) = not (# "clt" x y : bool #) + static member inline op_GreaterThanOrEqual(x: decimal, y: decimal) = Decimal.op_GreaterThanOrEqual (x, y) + static member inline op_GreaterThanOrEqual(x: string, y: string) = not (# "clt" (String.CompareOrdinal(x, y)) 0 : bool #) + + static member inline op_Equality(x: bool, y: bool) = (# "ceq" x y : bool #) + static member inline op_Equality(x: sbyte, y: sbyte) = (# "ceq" x y : bool #) + static member inline op_Equality(x: int16, y: int16) = (# "ceq" x y : bool #) + static member inline op_Equality(x: int32, y: int32) = (# "ceq" x y : bool #) + static member inline op_Equality(x: int64, y: int64) = (# "ceq" x y : bool #) + static member inline op_Equality(x: byte, y: byte) = (# "ceq" x y : bool #) + static member inline op_Equality(x: uint16, y: uint16) = (# "ceq" x y : bool #) + static member inline op_Equality(x: uint32, y: uint32) = (# "ceq" x y : bool #) + static member inline op_Equality(x: uint64, y: uint64) = (# "ceq" x y : bool #) + static member inline op_Equality(x: float, y: float) = (# "ceq" x y : bool #) + static member inline op_Equality(x: float32, y: float32) = (# "ceq" x y : bool #) + static member inline op_Equality(x: char, y: char) = (# "ceq" x y : bool #) + static member inline op_Equality(x: nativeint, y: nativeint) = (# "ceq" x y : bool #) + static member inline op_Equality(x: unativeint, y: unativeint) = (# "ceq" x y : bool #) + static member inline op_Equality(x: string, y: string) = String.Equals(x, y) + static member inline op_Equality(x: decimal, y: decimal) = Decimal.op_Equality(x, y) + + static member inline op_Inequality(x: bool, y: bool) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: sbyte, y: sbyte) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: int16, y: int16) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: int32, y: int32) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: int64, y: int64) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: byte, y: byte) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: uint16, y: uint16) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: uint32, y: uint32) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: uint64, y: uint64) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: float, y: float) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: float32, y: float32) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: char, y: char) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: nativeint, y: nativeint) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: unativeint, y: unativeint) = not (# "ceq" x y : bool #) + static member inline op_Inequality(x: string, y: string) = not (String.Equals(x, y)) + static member inline op_Inequality(x: decimal, y: decimal) = Decimal.op_Inequality(x, y) + + static member inline DivideByInt (x: decimal, n: int) = Decimal.Divide(x, Convert.ToDecimal(n)) + static member inline DivideByInt (x: float, n: int) = (# "div" x ((# "conv.r8" n : float #)) : float #) + static member inline DivideByInt (x: float32, n:int) = (# "div" x ((# "conv.r4" n : float32 #)) : float32 #) +#endif - [] type GenericZeroDynamicImplTable<'T>() = static let result : 'T = // The dynamic implementation @@ -2489,11 +3026,11 @@ namespace Microsoft.FSharp.Core elif aty.Equals(typeof) then unboxPrim<'T> (box 0.0) elif aty.Equals(typeof) then unboxPrim<'T> (box 0.0f) else - let pinfo = aty.GetProperty("Zero") + let pinfo = aty.GetTypeInfo().GetProperty("Zero") unboxPrim<'T> (pinfo.GetValue(null,null)) static member Result : 'T = result - [] + // TODO: rationalise these type GenericOneDynamicImplTable<'T>() = static let result : 'T = // The dynamic implementation @@ -2513,7 +3050,7 @@ namespace Microsoft.FSharp.Core elif aty.Equals(typeof) then unboxPrim<'T> (box 1.0) elif aty.Equals(typeof) then unboxPrim<'T> (box 1.0f) else - let pinfo = aty.GetProperty("One") + let pinfo = aty.GetTypeInfo().GetProperty("One") unboxPrim<'T> (pinfo.GetValue(null,null)) static member Result : 'T = result @@ -2521,6 +3058,7 @@ namespace Microsoft.FSharp.Core let GenericZeroDynamic<'T>() : 'T = GenericZeroDynamicImplTable<'T>.Result let GenericOneDynamic<'T>() : 'T = GenericOneDynamicImplTable<'T>.Result + // TODO: rationalise these let inline GenericZero< ^T when ^T : (static member Zero : ^T) > : ^T = GenericZeroDynamic<(^T)>() when ^T : int32 = 0 @@ -2537,10 +3075,10 @@ namespace Microsoft.FSharp.Core when ^T : byte = 0uy when ^T : decimal = 0M // According to the somewhat subtle rules of static optimizations, - // this condition is used whenever ^T is resolved to a nominal type + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available when ^T : ^T = (^T : (static member Zero : ^T) ()) - + // TODO: rationalise these let inline GenericOne< ^T when ^T : (static member One : ^T) > : ^T = GenericOneDynamic<(^T)>() when ^T : int32 = 1 @@ -2558,201 +3096,225 @@ namespace Microsoft.FSharp.Core when ^T : byte = 1uy when ^T : decimal = 1M // According to the somewhat subtle rules of static optimizations, - // this condition is used whenever ^T is resolved to a nominal type + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available // That is, not in the generic implementation of '+' when ^T : ^T = (^T : (static member One : ^T) ()) - [] - type GenericDivideByIntDynamicImplTable<'T>() = - static let result : ('T -> int -> 'T) = + let UnaryDynamicImpl nm : ('T -> 'U) = + let aty = typeof<'T> +#if FX_RESHAPED_REFLECTION + let minfo = aty.GetMethod(nm, [| aty |]) +#else + let staticBindingFlags = (# "" 0b111000 : BindingFlags #) // BindingFlags.Static ||| BindingFlags.Public ||| BindingFlags.NonPublic) + let minfo = aty.GetMethod(nm, staticBindingFlags, null, [| aty |], null ) +#endif + (fun x -> unboxPrim<_>(minfo.Invoke(null,[| box x|]))) + + let BinaryDynamicImpl nm : ('T -> 'U -> 'V) = + let aty = typeof<'T> + let bty = typeof<'U> +#if FX_RESHAPED_REFLECTION + let minfo = aty.GetMethod(nm,[| aty;bty |]) +#else + let staticBindingFlags = (# "" 0b111000 : BindingFlags #) // BindingFlags.Static ||| BindingFlags.Public ||| BindingFlags.NonPublic) + let minfo = aty.GetMethod(nm, staticBindingFlags, null, [| aty; bty |], null ) +#endif + (fun x y -> unboxPrim<_>(minfo.Invoke(null,[| box x; box y|]))) + + // Dynamic implementation of operator resolution, using BuiltInWitnesses as backing data + type UnaryOpDynamicImplTable<'OpInfo,'T,'U>() = + static let impl : ('T -> 'U) = // The dynamic implementation let aty = typeof<'T> - if aty.Equals(typeof) then unboxPrim<_> (box (fun (x:decimal) (n:int) -> System.Decimal.Divide(x, System.Convert.ToDecimal(n)))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:float) (n:int) -> (# "div" x ((# "conv.r8" n : float #)) : float #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:float32) (n:int) -> (# "div" x ((# "conv.r4" n : float32 #)) : float32 #))) - else - match aty.GetMethod("DivideByInt",[| aty; typeof |]) with - | null -> raise (NotSupportedException (SR.GetString(SR.dyInvDivByIntCoerce))) - | m -> (fun x n -> unboxPrim<_> (m.Invoke(null,[| box x; box n |]))) - - static member Result : ('T -> int -> 'T) = result + let bty = typeof<'U> - let DivideByIntDynamic<'T> x y = GenericDivideByIntDynamicImplTable<('T)>.Result x y + // Find the operator name +#if FX_RESHAPED_REFLECTION + let opNameMeth = typeof<'OpInfo>.GetMethod("get_Name", [| |]) +#else + let staticBindingFlags = (# "" 0b111000 : BindingFlags #) // BindingFlags.Static ||| BindingFlags.Public ||| BindingFlags.NonPublic) + let opNameMeth = typeof<'OpInfo>.GetMethod("get_Name", staticBindingFlags, null, [| |], null) +#endif + let opName = opNameMeth.Invoke(null, [| |]) :?> string +#if FX_RESHAPED_REFLECTION + let builtinNameMeth = typeof<'OpInfo>.GetTypeInfo().GetMethod("get_BuiltInName", [| |]) +#else + let builtinNameMeth = typeof<'OpInfo>.GetMethod("get_BuiltInName", staticBindingFlags, null, [| |], null) +#endif + let builtinName = match builtinNameMeth with null -> opName | _ -> builtinNameMeth.Invoke(null, [| |]) :?> string + + let meth = + let witnessesTy = typeof + let cmeth = + if builtinName.Equals("op_Explicit") then + let meths = witnessesTy.GetRuntimeMethods( (* staticBindingFlags *) ) + let mutable res = null + for meth in meths do + if meth.Name.Equals(builtinName) then + if (IntrinsicFunctions.GetArray (meth.GetParameters()) 0).ParameterType.Equals(aty) then + if meth.ReturnType.Equals(bty) then + res <- meth + res + else +#if FX_RESHAPED_REFLECTION + witnessesTy.GetMethod(builtinName, [| aty |]) +#else + witnessesTy.GetMethod(builtinName, staticBindingFlags, null, [| aty |], null) +#endif - let inline DivideByInt< ^T when ^T : (static member DivideByInt : ^T * int -> ^T) > (x:^T) (y:int) : ^T = - DivideByIntDynamic<'T> x y - when ^T : float = (# "div" x ((# "conv.r8" (y:int) : float #)) : float #) - when ^T : float32 = (# "div" x ((# "conv.r4" (y:int) : float32 #)) : float32 #) - when ^T : decimal = System.Decimal.Divide((retype x:decimal), System.Convert.ToDecimal(y)) - when ^T : ^T = (^T : (static member DivideByInt : ^T * int -> ^T) (x, y)) + match cmeth with + | null -> +#if FX_RESHAPED_REFLECTION + let ameth = aty.GetMethod(opName, [| aty |]) +#else + let ameth = aty.GetMethod(opName, staticBindingFlags, null, [| aty |], null) +#endif + match ameth with + | null -> raise (NotSupportedException (SR.GetString(SR.dyInvOpAddCoerce))) + | res -> res + | res -> res + (fun x -> unboxPrim<_> (meth.Invoke(null,[| box x |]))) + static member Impl : ('T -> 'U) = impl - // Dynamic implementation of addition operator resolution - [] - type AdditionDynamicImplTable<'T,'U,'V>() = + // Dynamic implementation of operator resolution, using BuiltInWitnesses as backing data + type BinaryOpDynamicImplTable<'OpInfo,'T,'U,'V>() = static let impl : ('T -> 'U -> 'V) = // The dynamic implementation let aty = typeof<'T> let bty = typeof<'U> - let cty = typeof<'V> - let dyn() = - let ameth = aty.GetMethod("op_Addition",[| aty; bty |]) - let bmeth = if aty.Equals(bty) then null else bty.GetMethod("op_Addition",[| aty; bty |]) - match ameth,bmeth with - | null, null -> raise (NotSupportedException (SR.GetString(SR.dyInvOpAddCoerce))) - | m,null | null,m -> (fun x y -> unboxPrim<_> (m.Invoke(null,[| box x; box y |]))) - | _ -> raise (NotSupportedException (SR.GetString(SR.dyInvOpAddOverload))) - - if aty.Equals(bty) && bty.Equals(cty) then - if aty.Equals(typeof) then unboxPrim<_> (box (fun (x:sbyte) (y:sbyte) -> (# "conv.i1" (# "add" x y : int32 #) : sbyte #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int16) (y:int16) -> (# "conv.i2" (# "add" x y : int32 #) : int16 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int32) (y:int32) -> (# "add" x y : int32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int64) (y:int64) -> (# "add" x y : int64 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:nativeint) (y:nativeint) -> (# "add" x y : nativeint #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:byte) (y:byte) -> (# "conv.u1" (# "add" x y : uint32 #) : byte #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint16) (y:uint16) -> (# "conv.u2" (# "add" x y : uint32 #) : uint16 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint32) (y:uint32) -> (# "add" x y : uint32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint64) (y:uint64) -> (# "add" x y : uint64 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:unativeint) (y:unativeint) -> (# "add" x y : unativeint #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:float) (y:float) -> (# "add" x y : float #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:float32) (y:float32) -> (# "add" x y : float32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:string) (y:string) -> System.String.Concat(x,y))) - else dyn() - else dyn() + + // Find the operator name +#if FX_RESHAPED_REFLECTION + let opNameMeth = typeof<'OpInfo>.GetMethod("get_Name", [| |]) +#else + let staticBindingFlags = (# "" 0b111000 : BindingFlags #) // BindingFlags.Static ||| BindingFlags.Public ||| BindingFlags.NonPublic) + let opNameMeth = typeof<'OpInfo>.GetMethod("get_Name", staticBindingFlags, null, [| |], null) +#endif + let opName = opNameMeth.Invoke(null, [| |]) :?> string +#if FX_RESHAPED_REFLECTION + let builtinNameMeth = typeof<'OpInfo>.GetMethod("get_BuiltInName", [| |]) +#else + let builtinNameMeth = typeof<'OpInfo>.GetMethod("get_BuiltInName", staticBindingFlags, null, [| |], null) +#endif + let builtinName = match builtinNameMeth with null -> opName | _ -> builtinNameMeth.Invoke(null, [| |]) :?> string + + let meth = + let witnessesTy = typeof +#if FX_RESHAPED_REFLECTION + let cmeth = witnessesTy.GetMethod(builtinName, [| aty; bty |]) +#else + let cmeth = witnessesTy.GetMethod(builtinName, staticBindingFlags, null, [| aty; bty |], null) +#endif + match cmeth with + | null -> +#if FX_RESHAPED_REFLECTION + let ameth = aty.GetMethod(opName, [| aty; bty |]) +#else + let ameth = aty.GetMethod(opName, staticBindingFlags, null, [| aty; bty |], null) +#endif + let bmeth = + if aty.Equals(bty) then null else +#if FX_RESHAPED_REFLECTION + bty.GetMethod(opName, [| aty; bty |]) +#else + bty.GetMethod(opName, staticBindingFlags, null, [| aty; bty |], null) +#endif + match ameth, bmeth with + | null, null -> raise (NotSupportedException (SR.GetString(SR.dyInvOpAddCoerce))) + | m, null | null, m -> m + | _ -> raise (NotSupportedException (SR.GetString(SR.dyInvOpAddOverload))) + | res -> res + (fun x y -> unboxPrim<_> (meth.Invoke(null,[| box x; box y |]))) static member Impl : ('T -> 'U -> 'V) = impl - let AdditionDynamic<'T,'U,'V> x y = AdditionDynamicImplTable<'T,'U,'V>.Impl x y + type OpAdditionInfo = static member Name = "op_Addition" + let AdditionDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y - // Dynamic implementation of checked addition operator resolution - [] - type CheckedAdditionDynamicImplTable<'T,'U,'V>() = - static let impl : ('T -> 'U -> 'V) = - // The dynamic implementation - let aty = typeof<'T> - let bty = typeof<'U> - let cty = typeof<'V> - let dyn() = - let ameth = aty.GetMethod("op_Addition",[| aty; bty |]) - let bmeth = if aty.Equals(bty) then null else bty.GetMethod("op_Addition",[| aty; bty |]) - match ameth,bmeth with - | null, null -> raise (NotSupportedException (SR.GetString(SR.dyInvOpAddCoerce))) - | m,null | null,m -> (fun x y -> unboxPrim<_> (m.Invoke(null,[| box x; box y |]))) - | _ -> raise (NotSupportedException (SR.GetString(SR.dyInvOpAddOverload))) - - if aty.Equals(bty) && bty.Equals(cty) then - if aty.Equals(typeof) then unboxPrim<_> (box (fun (x:sbyte) (y:sbyte) -> (# "conv.ovf.i1" (# "add.ovf" x y : int32 #) : sbyte #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int16) (y:int16) -> (# "conv.ovf.i2" (# "add.ovf" x y : int32 #) : int16 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int32) (y:int32) -> (# "add.ovf" x y : int32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int64) (y:int64) -> (# "add.ovf" x y : int64 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:nativeint) (y:nativeint) -> (# "add.ovf" x y : nativeint #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:byte) (y:byte) -> (# "conv.ovf.u1.un" (# "add.ovf.un" x y : uint32 #) : byte #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint16) (y:uint16) -> (# "conv.ovf.u2.un" (# "add.ovf.un" x y : uint32 #) : uint16 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:char) (y:char) -> (# "conv.ovf.u2.un" (# "add.ovf.un" x y : uint32 #) : char #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint32) (y:uint32) -> (# "add.ovf.un" x y : uint32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint64) (y:uint64) -> (# "add.ovf.un" x y : uint64 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:unativeint) (y:unativeint) -> (# "add.ovf.un" x y : unativeint #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:float) (y:float) -> (# "add" x y : float #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:float32) (y:float32) -> (# "add" x y : float32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:string) (y:string) -> System.String.Concat(x,y))) - else dyn() - else dyn() + type OpSubtractionInfo = static member Name = "op_Subtraction" + let SubtractionDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y + type OpMultiplyInfo = static member Name = "op_Multiply" + let MultiplyDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y - static member Impl : ('T -> 'U -> 'V) = impl + type OpDivisionInfo = static member Name = "op_Division" + let DivisionDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y - let CheckedAdditionDynamic<'T,'U,'V> x y = CheckedAdditionDynamicImplTable<'T,'U,'V>.Impl x y + type OpModulusInfo = static member Name = "op_Modulus" + let ModulusDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y + type OpUnaryNegationInfo = static member Name = "op_UnaryNegation" + let UnaryNegationDynamic<'T,'U> value = UnaryOpDynamicImplTable.Impl value - // Dynamic implementation of addition operator resolution - [] - type MultiplyDynamicImplTable<'T,'U,'V>() = - static let impl : ('T -> 'U -> 'V) = - // The dynamic implementation - let aty = typeof<'T> - let bty = typeof<'U> - let cty = typeof<'V> - let dyn() = - let ameth = aty.GetMethod("op_Multiply",[| aty; bty |]) - let bmeth = if aty.Equals(bty) then null else bty.GetMethod("op_Multiply",[| aty; bty |]) - match ameth,bmeth with - | null, null -> raise (NotSupportedException (SR.GetString(SR.dyInvOpMultCoerce))) - | m,null | null,m -> (fun x y -> unboxPrim<_> (m.Invoke(null,[| box x; box y |]))) - | _ -> raise (NotSupportedException (SR.GetString(SR.dyInvOpMultOverload))) - - if aty.Equals(bty) && bty.Equals(cty) then - if aty.Equals(typeof) then unboxPrim<_> (box (fun (x:sbyte) (y:sbyte) -> (# "conv.i1" (# "mul" x y : int32 #) : sbyte #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int16) (y:int16) -> (# "conv.i2" (# "mul" x y : int32 #) : int16 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int32) (y:int32) -> (# "mul" x y : int32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int64) (y:int64) -> (# "mul" x y : int64 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:nativeint) (y:nativeint) -> (# "mul" x y : nativeint #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:byte) (y:byte) -> (# "conv.u1" (# "mul" x y : uint32 #) : byte #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint16) (y:uint16) -> (# "conv.u2" (# "mul" x y : uint32 #) : uint16 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint32) (y:uint32) -> (# "mul" x y : uint32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint64) (y:uint64) -> (# "mul" x y : uint64 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:unativeint) (y:unativeint) -> (# "mul" x y : unativeint #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:float) (y:float) -> (# "mul" x y : float #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:float32) (y:float32) -> (# "mul" x y : float32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:string) (y:string) -> System.String.Concat(x,y))) - else dyn() - else dyn() + type OpCheckedAdditionInfo = + static member Name = "op_Addition" + static member BuiltInName = "op_CheckedAddition" + let CheckedAdditionDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y - static member Impl : ('T -> 'U -> 'V) = impl + type OpCheckedSubtractionInfo = + static member Name = "op_Subtraction" + static member BuiltInName = "op_CheckedSubtraction" + let CheckedSubtractionDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y - let MultiplyDynamic<'T,'U,'V> x y = MultiplyDynamicImplTable<'T,'U,'V>.Impl x y + type OpCheckedMultiplyInfo = + static member Name = "op_Multiply" + static member BuiltInName = "op_CheckedMultiply" + let CheckedMultiplyDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y - // Dynamic implementation of checked addition operator resolution - [] - type CheckedMultiplyDynamicImplTable<'T,'U,'V>() = - static let impl : ('T -> 'U -> 'V) = - // The dynamic implementation - let aty = typeof<'T> - let bty = typeof<'U> - let cty = typeof<'V> - let dyn() = - let ameth = aty.GetMethod("op_Multiply",[| aty; bty |]) - let bmeth = if aty.Equals(bty) then null else bty.GetMethod("op_Multiply",[| aty; bty |]) - match ameth,bmeth with - | null, null -> raise (NotSupportedException (SR.GetString(SR.dyInvOpMultCoerce))) - | m,null | null,m -> (fun x y -> unboxPrim<_> (m.Invoke(null,[| box x; box y |]))) - | _ -> raise (NotSupportedException (SR.GetString(SR.dyInvOpMultOverload))) - - if aty.Equals(bty) && bty.Equals(cty) then - if aty.Equals(typeof) then unboxPrim<_> (box (fun (x:sbyte) (y:sbyte) -> (# "conv.ovf.i1" (# "mul.ovf" x y : int32 #) : sbyte #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int16) (y:int16) -> (# "conv.ovf.i2" (# "mul.ovf" x y : int32 #) : int16 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int32) (y:int32) -> (# "mul.ovf" x y : int32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:int64) (y:int64) -> (# "mul.ovf" x y : int64 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:nativeint) (y:nativeint) -> (# "mul.ovf" x y : nativeint #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:byte) (y:byte) -> (# "conv.ovf.u1.un" (# "mul.ovf.un" x y : uint32 #) : byte #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint16) (y:uint16) -> (# "conv.ovf.u2.un" (# "mul.ovf.un" x y : uint16 #) : uint16 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint32) (y:uint32) -> (# "mul.ovf.un" x y : uint32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:uint64) (y:uint64) -> (# "mul.ovf.un" x y : uint64 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:unativeint) (y:unativeint) -> (# "mul.ovf.un" x y : unativeint #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:float) (y:float) -> (# "mul" x y : float #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:float32) (y:float32) -> (# "mul" x y : float32 #))) - elif aty.Equals(typeof) then unboxPrim<_> (box (fun (x:string) (y:string) -> System.String.Concat(x,y))) - else dyn() - else dyn() + type OpCheckedUnaryNegationInfo = + static member Name = "op_UnaryNegation" + static member BuiltInName = "op_CheckedUnaryNegation" + let CheckedUnaryNegationDynamic<'T,'U> value = UnaryOpDynamicImplTable.Impl value - static member Impl : ('T -> 'U -> 'V) = impl + type OpLeftShiftInfo = static member Name = "op_LeftShift" + let OpLeftShiftDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y - let CheckedMultiplyDynamic<'T,'U,'V> x y = CheckedMultiplyDynamicImplTable<'T,'U,'V>.Impl x y + type OpRightShiftInfo = static member Name = "op_RightShift" + let OpRightShiftDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y + type OpBitwiseAndInfo = static member Name = "op_BitwiseAnd" + let OpBitwiseAndDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y -namespace System + type OpBitwiseOrInfo = static member Name = "op_BitwiseOr" + let OpBitwiseOrDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y - open System - open System.Collections - open System.Collections.Generic - open System.Diagnostics - open System.Globalization - open System.Text - open Microsoft.FSharp.Core - open Microsoft.FSharp.Core.BasicInlinedOperations - open Microsoft.FSharp.Core.LanguagePrimitives - open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicOperators - open Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions + type OpBitwiseExclusiveOrInfo = static member Name = "op_ExclusiveOr" + let OpBitwiseExclusiveOrDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y + + type OpLogicalNotInfo = static member Name = "op_LogicalNot" + let OpLogicalNotDynamic<'T,'U> x = UnaryOpDynamicImplTable.Impl x + type OpExplicitInfo = static member Name = "op_Explicit" + let OpExplicitDynamic<'T,'U> x = UnaryOpDynamicImplTable.Impl x + + type OpLessThanInfo = static member Name = "op_LessThan" + let OpLessThanDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y + + type OpGreaterThanInfo = static member Name = "op_GreaterThan" + let OpGreaterThanDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y + + type OpLessThanOrEqualInfo = static member Name = "op_LessThanOrEqual" + let OpLessThanOrEqualDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y + + type OpGreaterThanOrEqualInfo = static member Name = "op_GreaterThanOrEqual" + let OpGreaterThanOrEqualDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y + + type OpEqualityInfo = static member Name = "op_Equality" + let OpEqualityDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y + + type OpInequalityInfo = static member Name = "op_Inequality" + let OpInequalityDynamic<'T,'U,'V> x y = BinaryOpDynamicImplTable.Impl x y + + type DivideByIntInfo = static member Name = "DivideByInt" + let DivideByIntDynamic<'T> x y = BinaryOpDynamicImplTable.Impl x y + + let inline DivideByInt< ^T when ^T : (static member DivideByInt : ^T * int -> ^T) > (x: ^T) (y: int) : ^T = + DivideByIntDynamic<'T> x y + when ^T : float = (# "div" x ((# "conv.r8" y : float #)) : float #) + when ^T : float32 = (# "div" x ((# "conv.r4" y : float32 #)) : float32 #) + when ^T : decimal = Decimal.Divide((# "" x : decimal #), Convert.ToDecimal(y)) + when ^T : ^T = (^T : (static member DivideByInt : ^T * int -> ^T) (x, y)) namespace Microsoft.FSharp.Core @@ -3117,10 +3679,7 @@ namespace Microsoft.FSharp.Core namespace Microsoft.FSharp.Collections - //------------------------------------------------------------------------- - // Lists - //------------------------------------------------------------------------- - + open System open System.Collections.Generic open System.Diagnostics open Microsoft.FSharp.Core @@ -3180,10 +3739,6 @@ namespace Microsoft.FSharp.Collections type ResizeArray<'T> = System.Collections.Generic.List<'T> - //------------------------------------------------------------------------- - // List (augmentation) - //------------------------------------------------------------------------- - module PrivateListHelpers = let notStarted() = raise (new System.InvalidOperationException(SR.GetString(SR.enumerationNotStarted))) @@ -3293,7 +3848,7 @@ namespace Microsoft.FSharp.Collections let n = l.Length let txt = if n > 1000 then "Length > 1000" - else System.String.Concat( [| "Length = "; n.ToString() |]) + else String.Concat( [| "Length = "; n.ToString() |]) txt member l.Head = match l with a :: _ -> a | [] -> raise (System.InvalidOperationException(SR.GetString(SR.inputListWasEmpty))) @@ -3477,7 +4032,7 @@ namespace Microsoft.FSharp.Core let inline (<<) func2 func1 x = func2 (func1 x) - let (^) (s1: string) (s2: string) = System.String.Concat(s1, s2) + let (^) (s1: string) (s2: string) = String.Concat(s1, s2) [] let defaultArg arg defaultValue = match arg with None -> defaultValue | Some v -> v @@ -3485,9 +4040,8 @@ namespace Microsoft.FSharp.Core [] let defaultValueArg arg defaultValue = match arg with ValueNone -> defaultValue | ValueSome v -> v - [] let inline (~-) (n: ^T) : ^T = - (^T : (static member (~-) : ^T -> ^T) (n)) + UnaryNegationDynamic<(^T), (^T)> n when ^T : int32 = (# "neg" n : int32 #) when ^T : float = (# "neg" n : float #) when ^T : float32 = (# "neg" n : float32 #) @@ -3495,8 +4049,11 @@ namespace Microsoft.FSharp.Core when ^T : int16 = (# "neg" n : int16 #) when ^T : nativeint = (# "neg" n : nativeint #) when ^T : sbyte = (# "neg" n : sbyte #) - when ^T : decimal = (# "" (System.Decimal.op_UnaryNegation((# "" n : decimal #))) : ^T #) - + when ^T : decimal = (# "" (Decimal.op_UnaryNegation((# "" n : decimal #))) : ^T #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member (~-) : ^T -> ^T) (n)) let inline (+) (x: ^T) (y: ^U) : ^V = AdditionDynamic<(^T),(^U),(^V)> x y @@ -3513,17 +4070,14 @@ namespace Microsoft.FSharp.Core when ^T : char and ^U : char = (# "conv.u2" (# "add" x y : uint32 #) : char #) when ^T : sbyte and ^U : sbyte = (# "conv.i1" (# "add" x y : int32 #) : sbyte #) when ^T : byte and ^U : byte = (# "conv.u1" (# "add" x y : uint32 #) : byte #) - when ^T : string and ^U : string = (# "" (System.String.Concat((# "" x : string #),(# "" y : string #))) : ^T #) - when ^T : decimal and ^U : decimal = (# "" (System.Decimal.op_Addition((# "" x : decimal #),(# "" y : decimal #))) : ^V #) - + when ^T : string and ^U : string = (# "" (String.Concat((# "" x : string #),(# "" y : string #))) : ^T #) + when ^T : decimal and ^U : decimal = (# "" (Decimal.op_Addition((# "" x : decimal #),(# "" y : decimal #))) : ^V #) // According to the somewhat subtle rules of static optimizations, - // this condition is used whenever ^T is resolved to a nominal type - // That is, not in the generic implementation of '+' + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available when ^T : ^T = ((^T or ^U): (static member (+) : ^T * ^U -> ^V) (x,y)) - [] let inline (-) (x: ^T) (y: ^U) : ^V = - ((^T or ^U): (static member (-) : ^T * ^U -> ^V) (x,y)) + SubtractionDynamic<(^T),(^U),(^V)> x y when ^T : int32 and ^U : int32 = (# "sub" x y : int32 #) when ^T : float and ^U : float = (# "sub" x y : float #) when ^T : float32 and ^U : float32 = (# "sub" x y : float32 #) @@ -3536,8 +4090,10 @@ namespace Microsoft.FSharp.Core when ^T : uint16 and ^U : uint16 = (# "conv.u2" (# "sub" x y : uint32 #) : uint16 #) when ^T : sbyte and ^U : sbyte = (# "conv.i1" (# "sub" x y : int32 #) : sbyte #) when ^T : byte and ^U : byte = (# "conv.u1" (# "sub" x y : uint32 #) : byte #) - when ^T : decimal and ^U : decimal = (# "" (System.Decimal.op_Subtraction((# "" x : decimal #),(# "" y : decimal #))) : ^V #) - + when ^T : decimal and ^U : decimal = (# "" (Decimal.op_Subtraction((# "" x : decimal #),(# "" y : decimal #))) : ^V #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = ((^T or ^U): (static member (-) : ^T * ^U -> ^V) (x,y)) let inline ( * ) (x: ^T) (y: ^U) : ^V = MultiplyDynamic<(^T),(^U),(^V)> x y @@ -3553,15 +4109,13 @@ namespace Microsoft.FSharp.Core when ^T : uint16 and ^U : uint16 = (# "conv.u2" (# "mul" x y : uint32 #) : uint16 #) when ^T : sbyte and ^U : sbyte = (# "conv.i1" (# "mul" x y : int32 #) : sbyte #) when ^T : byte and ^U : byte = (# "conv.u1" (# "mul" x y : uint32 #) : byte #) - when ^T : decimal and ^U : decimal = (# "" (System.Decimal.op_Multiply((# "" x : decimal #),(# "" y : decimal #))) : ^V #) + when ^T : decimal and ^U : decimal = (# "" (Decimal.op_Multiply((# "" x : decimal #),(# "" y : decimal #))) : ^V #) // According to the somewhat subtle rules of static optimizations, - // this condition is used whenever ^T is resolved to a nominal type - // That is, not in the generic implementation of '*' + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available when ^T : ^T = ((^T or ^U): (static member (*) : ^T * ^U -> ^V) (x,y)) - [] let inline ( / ) (x: ^T) (y: ^U) : ^V = - ((^T or ^U): (static member (/) : ^T * ^U -> ^V) (x,y)) + DivisionDynamic<(^T),(^U),(^V)> x y when ^T : int32 and ^U : int32 = (# "div" x y : int32 #) when ^T : float and ^U : float = (# "div" x y : float #) when ^T : float32 and ^U : float32 = (# "div" x y : float32 #) @@ -3574,11 +4128,13 @@ namespace Microsoft.FSharp.Core when ^T : uint16 and ^U : uint16 = (# "conv.u2" (# "div.un" x y : uint32 #) : uint16 #) when ^T : sbyte and ^U : sbyte = (# "conv.i1" (# "div" x y : int32 #) : sbyte #) when ^T : byte and ^U : byte = (# "conv.u1" (# "div.un" x y : uint32 #) : byte #) - when ^T : decimal and ^U : decimal = (# "" (System.Decimal.op_Division((# "" x : decimal #),(# "" y : decimal #))) : ^V #) + when ^T : decimal and ^U : decimal = (# "" (Decimal.op_Division((# "" x : decimal #),(# "" y : decimal #))) : ^V #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = ((^T or ^U): (static member (/) : ^T * ^U -> ^V) (x,y)) - [] let inline ( % ) (x: ^T) (y: ^U) : ^V = - ((^T or ^U): (static member (%) : ^T * ^U -> ^V) (x,y)) + ModulusDynamic<(^T),(^U),(^V)> x y when ^T : int32 and ^U : int32 = (# "rem" x y : int32 #) when ^T : float and ^U : float = (# "rem" x y : float #) when ^T : float32 and ^U : float32 = (# "rem" x y : float32 #) @@ -3591,11 +4147,13 @@ namespace Microsoft.FSharp.Core when ^T : uint16 and ^U : uint16 = (# "conv.u2" (# "rem.un" x y : uint32 #) : uint16 #) when ^T : sbyte and ^U : sbyte = (# "conv.i1" (# "rem" x y : int32 #) : sbyte #) when ^T : byte and ^U : byte = (# "conv.u1" (# "rem.un" x y : uint32 #) : byte #) - when ^T : decimal and ^U : decimal = (# "" (System.Decimal.op_Modulus((# "" x : decimal #),(# "" y : decimal #))) : ^V #) + when ^T : decimal and ^U : decimal = (# "" (Decimal.op_Modulus((# "" x : decimal #),(# "" y : decimal #))) : ^V #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = ((^T or ^U): (static member (%) : ^T * ^U -> ^V) (x,y)) - [] let inline (~+) (value: ^T) : ^T = - (^T: (static member (~+) : ^T -> ^T) (value)) + value when ^T : int32 = value when ^T : float = value when ^T : float32 = value @@ -3609,12 +4167,10 @@ namespace Microsoft.FSharp.Core when ^T : sbyte = value when ^T : byte = value when ^T : decimal = value + when ^T : ^T = (^T: (static member (~+) : ^T -> ^T) (value)) - let inline mask (n:int) (m:int) = (# "and" n m : int #) - - [] let inline (<<<) (value: ^T) (shift:int) : ^T = - (^T: (static member (<<<) : ^T * int -> ^T) (value,shift)) + OpLeftShiftDynamic<(^T),int,(^T)> value shift when ^T : int32 = (# "shl" value (mask shift 31) : int #) when ^T : uint32 = (# "shl" value (mask shift 31) : uint32 #) when ^T : int64 = (# "shl" value (mask shift 63) : int64 #) @@ -3625,10 +4181,12 @@ namespace Microsoft.FSharp.Core when ^T : uint16 = (# "conv.u2" (# "shl" value (mask shift 15) : uint32 #) : uint16 #) when ^T : sbyte = (# "conv.i1" (# "shl" value (mask shift 7 ) : int32 #) : sbyte #) when ^T : byte = (# "conv.u1" (# "shl" value (mask shift 7 ) : uint32 #) : byte #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T: (static member (<<<) : ^T * int -> ^T) (value,shift)) - [] let inline (>>>) (value: ^T) (shift:int) : ^T = - (^T: (static member (>>>) : ^T * int -> ^T) (value,shift)) + OpRightShiftDynamic<(^T),int,(^T)> value shift when ^T : int32 = (# "shr" value (mask shift 31) : int32 #) when ^T : uint32 = (# "shr.un" value (mask shift 31) : uint32 #) when ^T : int64 = (# "shr" value (mask shift 63) : int64 #) @@ -3639,10 +4197,12 @@ namespace Microsoft.FSharp.Core when ^T : uint16 = (# "conv.u2" (# "shr.un" value (mask shift 15) : uint32 #) : uint16 #) when ^T : sbyte = (# "conv.i1" (# "shr" value (mask shift 7 ) : int32 #) : sbyte #) when ^T : byte = (# "conv.u1" (# "shr.un" value (mask shift 7 ) : uint32 #) : byte #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T: (static member (>>>) : ^T * int -> ^T) (value, shift)) - [] let inline (&&&) (x: ^T) (y: ^T) : ^T = - (^T: (static member (&&&) : ^T * ^T -> ^T) (x,y)) + OpBitwiseAndDynamic<(^T),(^T),(^T)> x y when ^T : int32 = (# "and" x y : int32 #) when ^T : int64 = (# "and" x y : int64 #) when ^T : uint64 = (# "and" x y : uint64 #) @@ -3653,10 +4213,12 @@ namespace Microsoft.FSharp.Core when ^T : unativeint = (# "and" x y : unativeint #) when ^T : sbyte = (# "and" x y : sbyte #) when ^T : byte = (# "and" x y : byte #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T: (static member (&&&) : ^T * ^T -> ^T) (x, y)) - [] let inline (|||) (x: ^T) (y: ^T) : ^T = - (^T: (static member (|||) : ^T * ^T -> ^T) (x,y)) + OpBitwiseOrDynamic<(^T),(^T),(^T)> x y when ^T : int32 = (# "or" x y : int32 #) when ^T : int64 = (# "or" x y : int64 #) when ^T : uint64 = (# "or" x y : uint64 #) @@ -3667,10 +4229,12 @@ namespace Microsoft.FSharp.Core when ^T : unativeint = (# "or" x y : unativeint #) when ^T : sbyte = (# "or" x y : sbyte #) when ^T : byte = (# "or" x y : byte #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T: (static member (|||) : ^T * ^T -> ^T) (x, y)) - [] let inline (^^^) (x: ^T) (y: ^T) : ^T = - (^T: (static member (^^^) : ^T * ^T -> ^T) (x,y)) + OpBitwiseExclusiveOrDynamic<(^T),(^T),(^T)> x y when ^T : int32 = (# "xor" x y : int32 #) when ^T : int64 = (# "xor" x y : int64 #) when ^T : uint64 = (# "xor" x y : uint64 #) @@ -3681,10 +4245,12 @@ namespace Microsoft.FSharp.Core when ^T : unativeint = (# "xor" x y : unativeint #) when ^T : sbyte = (# "xor" x y : sbyte #) when ^T : byte = (# "xor" x y : byte #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T: (static member (^^^) : ^T * ^T -> ^T) (x, y)) - [] let inline (~~~) (value: ^T) : ^T = - (^T: (static member (~~~) : ^T -> ^T) (value)) + OpLogicalNotDynamic<(^T),(^T)> value when ^T : int32 = (# "not" value : int32 #) when ^T : int64 = (# "not" value : int64 #) when ^T : uint64 = (# "not" value : uint64 #) @@ -3695,6 +4261,9 @@ namespace Microsoft.FSharp.Core when ^T : uint16 = (# "conv.u2" (# "not" value : uint32 #) : uint16 #) when ^T : sbyte = (# "conv.i1" (# "not" value : int32 #) : sbyte #) when ^T : byte = (# "conv.u1" (# "not" value : uint32 #) : byte #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T: (static member (~~~) : ^T -> ^T) (value)) let inline castToString (x:'T) = (# "" x : string #) // internal @@ -3723,21 +4292,10 @@ namespace Microsoft.FSharp.Core [] let exit (exitcode:int) = System.Environment.Exit(exitcode); failwith "System.Environment.Exit did not exit!" - let inline parseByte (s:string) = (# "conv.ovf.u1" (ParseUInt32 s) : byte #) - let inline ParseSByte (s:string) = (# "conv.ovf.i1" (ParseInt32 s) : sbyte #) - let inline ParseInt16 (s:string) = (# "conv.ovf.i2" (ParseInt32 s) : int16 #) - let inline ParseUInt16 (s:string) = (# "conv.ovf.u2" (ParseUInt32 s) : uint16 #) - let inline ParseIntPtr (s:string) = (# "conv.ovf.i" (ParseInt64 s) : nativeint #) - let inline ParseUIntPtr (s:string) = (# "conv.ovf.u" (ParseInt64 s) : unativeint #) - let inline ParseDouble (s:string) = Double.Parse(removeUnderscores s,NumberStyles.Float, CultureInfo.InvariantCulture) - let inline ParseSingle (s:string) = Single.Parse(removeUnderscores s,NumberStyles.Float, CultureInfo.InvariantCulture) - - - [] [] let inline byte (value: ^T) = - (^T : (static member op_Explicit: ^T -> byte) (value)) - when ^T : string = parseByte (castToString value) + OpExplicitDynamic<(^T), byte> value + when ^T : string = ParseByte (castToString value) when ^T : float = (# "conv.u1" value : byte #) when ^T : float32 = (# "conv.u1" value : byte #) when ^T : int64 = (# "conv.u1" value : byte #) @@ -3751,11 +4309,13 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.u1" value : byte #) when ^T : unativeint = (# "conv.u1" value : byte #) when ^T : byte = (# "conv.u1" value : byte #) - - [] + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> byte) (value)) + [] let inline sbyte (value: ^T) = - (^T : (static member op_Explicit: ^T -> sbyte) (value)) + OpExplicitDynamic<(^T), sbyte> value when ^T : string = ParseSByte (castToString value) when ^T : float = (# "conv.i1" value : sbyte #) when ^T : float32 = (# "conv.i1" value : sbyte #) @@ -3770,11 +4330,13 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.i1" value : sbyte #) when ^T : unativeint = (# "conv.i1" value : sbyte #) when ^T : byte = (# "conv.i1" value : sbyte #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> sbyte) (value)) - [] [] let inline uint16 (value: ^T) = - (^T : (static member op_Explicit: ^T -> uint16) (value)) + OpExplicitDynamic<(^T), uint16> value when ^T : string = ParseUInt16 (castToString value) when ^T : float = (# "conv.u2" value : uint16 #) when ^T : float32 = (# "conv.u2" value : uint16 #) @@ -3789,11 +4351,13 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.u2" value : uint16 #) when ^T : unativeint = (# "conv.u2" value : uint16 #) when ^T : byte = (# "conv.u2" value : uint16 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> uint16) (value)) - [] [] let inline int16 (value: ^T) = - (^T : (static member op_Explicit: ^T -> int16) (value)) + OpExplicitDynamic<(^T), int16> value when ^T : string = ParseInt16 (castToString value) when ^T : float = (# "conv.i2" value : int16 #) when ^T : float32 = (# "conv.i2" value : int16 #) @@ -3808,18 +4372,18 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.i2" value : int16 #) when ^T : unativeint = (# "conv.i2" value : int16 #) when ^T : byte = (# "conv.i2" value : int16 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> int16) (value)) - [] [] let inline uint32 (value: ^T) = - (^T : (static member op_Explicit: ^T -> uint32) (value)) + OpExplicitDynamic<(^T), uint32> value when ^T : string = ParseUInt32 (castToString value) when ^T : float = (# "conv.u4" value : uint32 #) when ^T : float32 = (# "conv.u4" value : uint32 #) - when ^T : int64 = (# "conv.u4" value : uint32 #) when ^T : nativeint = (# "conv.u4" value : uint32 #) - // For integers shorter that 32 bits, we must first // sign-widen the signed integer to 32 bits, and then // "convert" from signed int32 to unsigned int32 @@ -3827,36 +4391,38 @@ namespace Microsoft.FSharp.Core when ^T : int32 = (# "" value : uint32 #) when ^T : int16 = (# "" value : uint32 #) when ^T : sbyte = (# "" value : uint32 #) - when ^T : uint64 = (# "conv.u4" value : uint32 #) when ^T : uint32 = (# "conv.u4" value : uint32 #) when ^T : uint16 = (# "conv.u4" value : uint32 #) when ^T : char = (# "conv.u4" value : uint32 #) when ^T : unativeint = (# "conv.u4" value : uint32 #) when ^T : byte = (# "conv.u4" value : uint32 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> uint32) (value)) - [] [] let inline int32 (value: ^T) = - (^T : (static member op_Explicit: ^T -> int32) (value)) + OpExplicitDynamic<(^T), int32> value when ^T : string = ParseInt32 (castToString value) when ^T : float = (# "conv.i4" value : int32 #) when ^T : float32 = (# "conv.i4" value : int32 #) when ^T : int64 = (# "conv.i4" value : int32 #) when ^T : nativeint = (# "conv.i4" value : int32 #) - // For integers shorter that 32 bits, we sign-widen the signed integer to 32 bits // This is a no-op on IL stack (ECMA 335 Part III 1.5 Tables 8 & 9) when ^T : int32 = (# "" value : int32 #) when ^T : int16 = (# "" value : int32 #) when ^T : sbyte = (# "" value : int32 #) - when ^T : uint64 = (# "conv.i4" value : int32 #) when ^T : uint32 = (# "" value : int32 #) // Signed<->Unsigned conversion is a no-op on IL stack when ^T : uint16 = (# "conv.i4" value : int32 #) when ^T : char = (# "conv.i4" value : int32 #) when ^T : unativeint = (# "conv.i4" value : int32 #) when ^T : byte = (# "conv.i4" value : int32 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> int32) (value)) [] let inline int value = int32 value @@ -3879,14 +4445,12 @@ namespace Microsoft.FSharp.Core [] let nanf = System.Single.NaN - [] [] let inline uint64 (value: ^T) = - (^T : (static member op_Explicit: ^T -> uint64) (value)) + OpExplicitDynamic<(^T), uint64> value when ^T : string = ParseUInt64 (castToString value) when ^T : float = (# "conv.u8" value : uint64 #) when ^T : float32 = (# "conv.u8" value : uint64 #) - // we must first sign-widen the signed integer to 64 bits, and then // "convert" from signed int64 to unsigned int64 // conv.i8 sign-widens the input, and on IL stack, @@ -3896,19 +4460,19 @@ namespace Microsoft.FSharp.Core when ^T : int16 = (# "conv.i8" value : uint64 #) when ^T : nativeint = (# "conv.i8" value : uint64 #) when ^T : sbyte = (# "conv.i8" value : uint64 #) - - when ^T : uint64 = (# "" value : uint64 #) when ^T : uint32 = (# "conv.u8" value : uint64 #) when ^T : uint16 = (# "conv.u8" value : uint64 #) when ^T : char = (# "conv.u8" value : uint64 #) when ^T : unativeint = (# "conv.u8" value : uint64 #) when ^T : byte = (# "conv.u8" value : uint64 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> uint64) (value)) - [] [] let inline int64 (value: ^T) = - (^T : (static member op_Explicit: ^T -> int64) (value)) + OpExplicitDynamic<(^T), int64> value when ^T : string = ParseInt64 (castToString value) when ^T : float = (# "conv.i8" value : int64 #) when ^T : float32 = (# "conv.i8" value : int64 #) @@ -3917,7 +4481,6 @@ namespace Microsoft.FSharp.Core when ^T : int16 = (# "conv.i8" value : int64 #) when ^T : nativeint = (# "conv.i8" value : int64 #) when ^T : sbyte = (# "conv.i8" value : int64 #) - // When converting unsigned integer, we should zero-widen them, NOT sign-widen // No-op for uint64, conv.u8 for uint32, for smaller types conv.u8 and conv.i8 are identical. // For nativeint, conv.u8 works correctly both in 32 bit and 64 bit case. @@ -3927,11 +4490,13 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.u8" value : int64 #) when ^T : unativeint = (# "conv.u8" value : int64 #) when ^T : byte = (# "conv.u8" value : int64 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> int64) (value)) - [] [] let inline float32 (value: ^T) = - (^T : (static member op_Explicit: ^T -> float32) (value)) + OpExplicitDynamic<(^T), float32> value when ^T : string = ParseSingle (castToString value) when ^T : float = (# "conv.r4" value : float32 #) // NOTE: float32 should convert its argument to 32-bit float even when applied to a higher precision float stored in a register. See devdiv2#49888. @@ -3947,11 +4512,13 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.r.un conv.r4" value : float32 #) when ^T : unativeint = (# "conv.r.un conv.r4" value : float32 #) when ^T : byte = (# "conv.r.un conv.r4" value : float32 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> float32) (value)) - [] [] let inline float (value: ^T) = - (^T : (static member op_Explicit: ^T -> float) (value)) + OpExplicitDynamic<(^T), float> value when ^T : string = ParseDouble (castToString value) // NOTE: float should convert its argument to 64-bit float even when applied to a higher precision float stored in a register. See devdiv2#49888. when ^T : float = (# "conv.r8" value : float #) @@ -3967,40 +4534,38 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.r.un conv.r8" value : float #) when ^T : unativeint = (# "conv.r.un conv.r8" value : float #) when ^T : byte = (# "conv.r.un conv.r8" value : float #) - when ^T : decimal = (System.Convert.ToDouble((# "" value : decimal #))) + when ^T : decimal = (Convert.ToDouble((# "" value : decimal #))) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> float) (value)) - [] [] let inline decimal (value: ^T) = - (^T : (static member op_Explicit: ^T -> decimal) (value)) - when ^T : string = (System.Decimal.Parse(castToString value,NumberStyles.Float,CultureInfo.InvariantCulture)) - when ^T : float = (System.Convert.ToDecimal((# "" value : float #))) - when ^T : float32 = (System.Convert.ToDecimal((# "" value : float32 #))) - when ^T : int64 = (System.Convert.ToDecimal((# "" value : int64 #))) - when ^T : int32 = (System.Convert.ToDecimal((# "" value : int32 #))) - when ^T : int16 = (System.Convert.ToDecimal((# "" value : int16 #))) - when ^T : nativeint = (System.Convert.ToDecimal(int64 (# "" value : nativeint #))) - when ^T : sbyte = (System.Convert.ToDecimal((# "" value : sbyte #))) - when ^T : uint64 = (System.Convert.ToDecimal((# "" value : uint64 #))) - when ^T : uint32 = (System.Convert.ToDecimal((# "" value : uint32 #))) - when ^T : uint16 = (System.Convert.ToDecimal((# "" value : uint16 #))) - when ^T : unativeint = (System.Convert.ToDecimal(uint64 (# "" value : unativeint #))) - when ^T : byte = (System.Convert.ToDecimal((# "" value : byte #))) + OpExplicitDynamic<(^T), decimal> value + when ^T : string = (Decimal.Parse(castToString value,NumberStyles.Float,CultureInfo.InvariantCulture)) + when ^T : float = (Convert.ToDecimal((# "" value : float #))) + when ^T : float32 = (Convert.ToDecimal((# "" value : float32 #))) + when ^T : int64 = (Convert.ToDecimal((# "" value : int64 #))) + when ^T : int32 = (Convert.ToDecimal((# "" value : int32 #))) + when ^T : int16 = (Convert.ToDecimal((# "" value : int16 #))) + when ^T : nativeint = (Convert.ToDecimal(int64 (# "" value : nativeint #))) + when ^T : sbyte = (Convert.ToDecimal((# "" value : sbyte #))) + when ^T : uint64 = (Convert.ToDecimal((# "" value : uint64 #))) + when ^T : uint32 = (Convert.ToDecimal((# "" value : uint32 #))) + when ^T : uint16 = (Convert.ToDecimal((# "" value : uint16 #))) + when ^T : unativeint = (Convert.ToDecimal(uint64 (# "" value : unativeint #))) + when ^T : byte = (Convert.ToDecimal((# "" value : byte #))) when ^T : decimal = (# "" value : decimal #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> decimal) (value)) - // Recall type names. - // Framework names: sbyte, byte, int16, uint16, int32, uint32, int64, uint64, single, double. - // C# names: sbyte, byte, short, ushort, int, uint, long, ulong, single, double. - // F# names: sbyte, byte, int16, uint16, int, uint32, int64, uint64, float32, float. - - [] [] let inline unativeint (value: ^T) = - (^T : (static member op_Explicit: ^T -> unativeint) (value)) + OpExplicitDynamic<(^T), unativeint> value when ^T : string = ParseUIntPtr (castToString value) when ^T : float = (# "conv.u" value : unativeint #) when ^T : float32 = (# "conv.u" value : unativeint #) - // Narrower signed types we sign-extend. // Same length signed types we leave as such (so -1 gets reinterpreted as unsigned MaxValue). // Wider signed types we truncate. @@ -4010,28 +4575,27 @@ namespace Microsoft.FSharp.Core when ^T : int16 = (# "conv.i" value : unativeint #) when ^T : nativeint = (# "" value : unativeint #) when ^T : sbyte = (# "conv.i" value : unativeint #) - when ^T : uint64 = (# "conv.u" value : unativeint #) when ^T : uint32 = (# "conv.u" value : unativeint #) when ^T : uint16 = (# "conv.u" value : unativeint #) when ^T : char = (# "conv.u" value : unativeint #) when ^T : unativeint = (# "" value : unativeint #) when ^T : byte = (# "conv.u" value : unativeint #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> unativeint) (value)) - [] [] let inline nativeint (value: ^T) = - (^T : (static member op_Explicit: ^T -> nativeint) (value)) + OpExplicitDynamic<(^T), nativeint> value when ^T : string = ParseIntPtr (castToString value) when ^T : float = (# "conv.i" value : nativeint #) when ^T : float32 = (# "conv.i" value : nativeint #) - when ^T : int64 = (# "conv.i" value : nativeint #) when ^T : int32 = (# "conv.i" value : nativeint #) when ^T : int16 = (# "conv.i" value : nativeint #) when ^T : nativeint = (# "conv.i" value : nativeint #) when ^T : sbyte = (# "conv.i" value : nativeint #) - // Narrower unsigned types we zero-extend. // Same length unsigned types we leave as such (so unsigned MaxValue (all-bits-set) gets reinterpreted as -1). // Wider unsigned types we truncate. @@ -4042,6 +4606,9 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.u" value : nativeint #) when ^T : unativeint = (# "" value : nativeint #) when ^T : byte = (# "conv.i" value : nativeint #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> nativeint) (value)) [] let inline string (value: ^T) = @@ -4062,10 +4629,9 @@ namespace Microsoft.FSharp.Core when ^T : unativeint = (# "" value : unativeint #).ToString() when ^T : byte = (# "" value : byte #).ToString("g",CultureInfo.InvariantCulture) - [] [] let inline char (value: ^T) = - (^T : (static member op_Explicit: ^T -> char) (value)) + OpExplicitDynamic<(^T), char> value when ^T : string = (System.Char.Parse(castToString value)) when ^T : float = (# "conv.u2" value : char #) when ^T : float32 = (# "conv.u2" value : char #) @@ -4080,12 +4646,14 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.u2" value : char #) when ^T : unativeint = (# "conv.u2" value : char #) when ^T : byte = (# "conv.u2" value : char #) - + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member op_Explicit: ^T -> char) (value)) module NonStructuralComparison = /// Static less-than with static optimizations for some well-known cases. let inline (<) (x:^T) (y:^U) = - ((^T or ^U): (static member (<) : ^T * ^U -> bool) (x,y)) + OpLessThanDynamic<(^T), (^U), bool> x y when ^T : bool = (# "clt" x y : bool #) when ^T : sbyte = (# "clt" x y : bool #) when ^T : int16 = (# "clt" x y : bool #) @@ -4100,12 +4668,15 @@ namespace Microsoft.FSharp.Core when ^T : float = (# "clt" x y : bool #) when ^T : float32= (# "clt" x y : bool #) when ^T : char = (# "clt" x y : bool #) - when ^T : decimal = System.Decimal.op_LessThan ((# "" x:decimal #), (# "" y:decimal #)) - when ^T : string = (# "clt" (System.String.CompareOrdinal((# "" x : string #),(# "" y : string #))) 0 : bool #) + when ^T : decimal = Decimal.op_LessThan ((# "" x:decimal #), (# "" y:decimal #)) + when ^T : string = (# "clt" (String.CompareOrdinal((# "" x : string #),(# "" y : string #))) 0 : bool #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = ((^T or ^U): (static member (<) : ^T * ^U -> bool) (x,y)) /// Static greater-than with static optimizations for some well-known cases. let inline (>) (x:^T) (y:^U) = - ((^T or ^U): (static member (>) : ^T * ^U -> bool) (x,y)) + OpGreaterThanDynamic<(^T), (^U), bool> x y when 'T : bool = (# "cgt" x y : bool #) when 'T : sbyte = (# "cgt" x y : bool #) when 'T : int16 = (# "cgt" x y : bool #) @@ -4120,12 +4691,15 @@ namespace Microsoft.FSharp.Core when 'T : float = (# "cgt" x y : bool #) when 'T : float32 = (# "cgt" x y : bool #) when 'T : char = (# "cgt" x y : bool #) - when 'T : decimal = System.Decimal.op_GreaterThan ((# "" x:decimal #), (# "" y:decimal #)) - when ^T : string = (# "cgt" (System.String.CompareOrdinal((# "" x : string #),(# "" y : string #))) 0 : bool #) + when 'T : decimal = Decimal.op_GreaterThan ((# "" x:decimal #), (# "" y:decimal #)) + when ^T : string = (# "cgt" (String.CompareOrdinal((# "" x : string #),(# "" y : string #))) 0 : bool #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = ((^T or ^U): (static member (>) : ^T * ^U -> bool) (x,y)) /// Static less-than-or-equal with static optimizations for some well-known cases. let inline (<=) (x:^T) (y:^U) = - ((^T or ^U): (static member (<=) : ^T * ^U -> bool) (x,y)) + OpLessThanOrEqualDynamic<(^T), (^U), bool> x y when 'T : bool = not (# "cgt" x y : bool #) when 'T : sbyte = not (# "cgt" x y : bool #) when 'T : int16 = not (# "cgt" x y : bool #) @@ -4140,12 +4714,15 @@ namespace Microsoft.FSharp.Core when 'T : float = not (# "cgt.un" x y : bool #) when 'T : float32 = not (# "cgt.un" x y : bool #) when 'T : char = not (# "cgt" x y : bool #) - when 'T : decimal = System.Decimal.op_LessThanOrEqual ((# "" x:decimal #), (# "" y:decimal #)) - when ^T : string = not (# "cgt" (System.String.CompareOrdinal((# "" x : string #),(# "" y : string #))) 0 : bool #) + when 'T : decimal = Decimal.op_LessThanOrEqual ((# "" x:decimal #), (# "" y:decimal #)) + when ^T : string = not (# "cgt" (String.CompareOrdinal((# "" x : string #),(# "" y : string #))) 0 : bool #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = ((^T or ^U): (static member (<=) : ^T * ^U -> bool) (x,y)) /// Static greater-than-or-equal with static optimizations for some well-known cases. let inline (>=) (x:^T) (y:^U) = - ((^T or ^U): (static member (>=) : ^T * ^U -> bool) (x,y)) + OpGreaterThanOrEqualDynamic<(^T), (^U), bool> x y when 'T : bool = not (# "clt" x y : bool #) when 'T : sbyte = not (# "clt" x y : bool #) when 'T : int16 = not (# "clt" x y : bool #) @@ -4160,13 +4737,15 @@ namespace Microsoft.FSharp.Core when 'T : float = not (# "clt.un" x y : bool #) when 'T : float32 = not (# "clt.un" x y : bool #) when 'T : char = not (# "clt" x y : bool #) - when 'T : decimal = System.Decimal.op_GreaterThanOrEqual ((# "" x:decimal #), (# "" y:decimal #)) - when ^T : string = not (# "clt" (System.String.CompareOrdinal((# "" x : string #),(# "" y : string #))) 0 : bool #) - + when 'T : decimal = Decimal.op_GreaterThanOrEqual ((# "" x:decimal #), (# "" y:decimal #)) + when ^T : string = not (# "clt" (String.CompareOrdinal((# "" x : string #),(# "" y : string #))) 0 : bool #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = ((^T or ^U): (static member (>=) : ^T * ^U -> bool) (x,y)) /// Static greater-than-or-equal with static optimizations for some well-known cases. let inline (=) (x:^T) (y:^T) = - (^T : (static member (=) : ^T * ^T -> bool) (x,y)) + OpEqualityDynamic<(^T), (^T), bool> x y when ^T : bool = (# "ceq" x y : bool #) when ^T : sbyte = (# "ceq" x y : bool #) when ^T : int16 = (# "ceq" x y : bool #) @@ -4181,11 +4760,12 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "ceq" x y : bool #) when ^T : nativeint = (# "ceq" x y : bool #) when ^T : unativeint = (# "ceq" x y : bool #) - when ^T : string = System.String.Equals((# "" x : string #),(# "" y : string #)) - when ^T : decimal = System.Decimal.op_Equality((# "" x:decimal #), (# "" y:decimal #)) + when ^T : string = String.Equals((# "" x : string #),(# "" y : string #)) + when ^T : decimal = Decimal.op_Equality((# "" x:decimal #), (# "" y:decimal #)) + when ^T : ^T = (^T : (static member (=) : ^T * ^T -> bool) (x,y)) let inline (<>) (x:^T) (y:^T) = - (^T : (static member (<>) : ^T * ^T -> bool) (x,y)) + OpInequalityDynamic<(^T), (^T), bool> x y when ^T : bool = not (# "ceq" x y : bool #) when ^T : sbyte = not (# "ceq" x y : bool #) when ^T : int16 = not (# "ceq" x y : bool #) @@ -4200,9 +4780,9 @@ namespace Microsoft.FSharp.Core when ^T : char = not (# "ceq" x y : bool #) when ^T : nativeint = not (# "ceq" x y : bool #) when ^T : unativeint = not (# "ceq" x y : bool #) - when ^T : string = not (System.String.Equals((# "" x : string #),(# "" y : string #))) - when ^T : decimal = System.Decimal.op_Inequality((# "" x:decimal #), (# "" y:decimal #)) - + when ^T : string = not (String.Equals((# "" x : string #),(# "" y : string #))) + when ^T : decimal = Decimal.op_Inequality((# "" x:decimal #), (# "" y:decimal #)) + when ^T : ^T = (^T : (static member (<>) : ^T * ^T -> bool) (x,y)) // static comparison (ER mode) with static optimizations for some well-known cases [] @@ -4231,10 +4811,10 @@ namespace Microsoft.FSharp.Core else (# "ceq" e1 e1 : int #) when ^T : char = if (# "clt.un" e1 e2 : bool #) then (-1) else (# "cgt.un" e1 e2 : int #) when ^T : string = - // NOTE: we don't have to null check here because System.String.CompareOrdinal + // NOTE: we don't have to null check here because String.CompareOrdinal // gives reliable results on null values. - System.String.CompareOrdinal((# "" e1 : string #),(# "" e2 : string #)) - when ^T : decimal = System.Decimal.Compare((# "" e1:decimal #), (# "" e2:decimal #)) + String.CompareOrdinal((# "" e1 : string #),(# "" e2 : string #)) + when ^T : decimal = Decimal.Compare((# "" e1:decimal #), (# "" e2:decimal #)) [] let inline max (e1: ^T) (e2: ^T) = @@ -4385,16 +4965,14 @@ namespace Microsoft.FSharp.Core when ^T : char and ^U : char = (# "conv.ovf.u2.un" (# "add.ovf.un" x y : uint32 #) : char #) when ^T : sbyte and ^U : sbyte = (# "conv.ovf.i1" (# "add.ovf" x y : int32 #) : sbyte #) when ^T : byte and ^U : byte = (# "conv.ovf.u1.un" (# "add.ovf.un" x y : uint32 #) : byte #) - when ^T : string and ^U : string = (# "" (System.String.Concat((# "" x : string #),(# "" y : string #))) : ^T #) - when ^T : decimal and ^U : decimal = (# "" (System.Decimal.op_Addition((# "" x : decimal #),(# "" y : decimal #))) : ^V #) + when ^T : string and ^U : string = (# "" (String.Concat((# "" x : string #),(# "" y : string #))) : ^T #) + when ^T : decimal and ^U : decimal = (# "" (Decimal.op_Addition((# "" x : decimal #),(# "" y : decimal #))) : ^V #) // According to the somewhat subtle rules of static optimizations, - // this condition is used whenever ^T is resolved to a nominal type - // That is, not in the generic implementation of '+' + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available when ^T : ^T = ((^T or ^U): (static member (+) : ^T * ^U -> ^V) (x,y)) - [] let inline (-) (x: ^T) (y: ^U) : ^V = - ((^T or ^U): (static member (-) : ^T * ^U -> ^V) (x,y)) + CheckedSubtractionDynamic<(^T),(^U),(^V)> x y when ^T : int32 and ^U : int32 = (# "sub.ovf" x y : int32 #) when ^T : float and ^U : float = (# "sub" x y : float #) when ^T : float32 and ^U : float32 = (# "sub" x y : float32 #) @@ -4407,11 +4985,13 @@ namespace Microsoft.FSharp.Core when ^T : uint16 and ^U : uint16 = (# "conv.ovf.u2.un" (# "sub.ovf.un" x y : uint32 #) : uint16 #) when ^T : sbyte and ^U : sbyte = (# "conv.ovf.i1" (# "sub.ovf" x y : int32 #) : sbyte #) when ^T : byte and ^U : byte = (# "conv.ovf.u1.un" (# "sub.ovf.un" x y : uint32 #) : byte #) - when ^T : decimal and ^U : decimal = (# "" (System.Decimal.op_Subtraction((# "" x : decimal #),(# "" y : decimal #))) : ^V #) + when ^T : decimal and ^U : decimal = (# "" (Decimal.op_Subtraction((# "" x : decimal #),(# "" y : decimal #))) : ^V #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = ((^T or ^U): (static member (-) : ^T * ^U -> ^V) (x,y)) - [] let inline (~-) (value: ^T) : ^T = - (^T : (static member (~-) : ^T -> ^T) (value)) + CheckedUnaryNegationDynamic<(^T),(^T)> value when ^T : int32 = (# "sub.ovf" 0 value : int32 #) when ^T : float = (# "neg" value : float #) when ^T : float32 = (# "neg" value : float32 #) @@ -4419,7 +4999,10 @@ namespace Microsoft.FSharp.Core when ^T : int16 = (# "sub.ovf" 0s value : int16 #) when ^T : nativeint = (# "sub.ovf" 0n value : nativeint #) when ^T : sbyte = (# "sub.ovf" 0y value : sbyte #) - when ^T : decimal = (# "" (System.Decimal.op_UnaryNegation((# "" value : decimal #))) : ^T #) + when ^T : decimal = (# "" (Decimal.op_UnaryNegation((# "" value : decimal #))) : ^T #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + when ^T : ^T = (^T : (static member (~-) : ^T -> ^T) (value)) let inline ( * ) (x: ^T) (y: ^U) : ^V = CheckedMultiplyDynamic<(^T),(^U),(^V)> x y @@ -4435,17 +5018,16 @@ namespace Microsoft.FSharp.Core when ^T : unativeint and ^U : unativeint = (# "mul.ovf.un" x y : unativeint #) when ^T : float and ^U : float = (# "mul" x y : float #) when ^T : float32 and ^U : float32 = (# "mul" x y : float32 #) - when ^T : decimal and ^U : decimal = (# "" (System.Decimal.op_Multiply((# "" x : decimal #),(# "" y : decimal #))) : ^V #) + when ^T : decimal and ^U : decimal = (# "" (Decimal.op_Multiply((# "" x : decimal #),(# "" y : decimal #))) : ^V #) // According to the somewhat subtle rules of static optimizations, - // this condition is used whenever ^T is resolved to a nominal type + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available // That is, not in the generic implementation of '*' when ^T : ^T = ((^T or ^U): (static member (*) : ^T * ^U -> ^V) (x,y)) - [] [] let inline byte (value: ^T) = - (^T : (static member op_Explicit: ^T -> byte) (value)) - when ^T : string = parseByte (castToString value) + OpExplicitDynamic<(^T),byte> value + when ^T : string = ParseByte (castToString value) when ^T : float = (# "conv.ovf.u1" value : byte #) when ^T : float32 = (# "conv.ovf.u1" value : byte #) when ^T : int64 = (# "conv.ovf.u1" value : byte #) @@ -4459,11 +5041,14 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.u1.un" value : byte #) when ^T : unativeint = (# "conv.ovf.u1.un" value : byte #) when ^T : byte = (# "conv.ovf.u1.un" value : byte #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> byte) (value)) - [] [] let inline sbyte (value: ^T) = - (^T : (static member op_Explicit: ^T -> sbyte) (value)) + OpExplicitDynamic<(^T),sbyte> value when ^T : string = ParseSByte (castToString value) when ^T : float = (# "conv.ovf.i1" value : sbyte #) when ^T : float32 = (# "conv.ovf.i1" value : sbyte #) @@ -4478,11 +5063,14 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.i1.un" value : sbyte #) when ^T : unativeint = (# "conv.ovf.i1.un" value : sbyte #) when ^T : byte = (# "conv.ovf.i1.un" value : sbyte #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> sbyte) (value)) - [] [] let inline uint16 (value: ^T) = - (^T : (static member op_Explicit: ^T -> uint16) (value)) + OpExplicitDynamic<(^T),uint16> value when ^T : string = ParseUInt16 (castToString value) when ^T : float = (# "conv.ovf.u2" value : uint16 #) when ^T : float32 = (# "conv.ovf.u2" value : uint16 #) @@ -4497,11 +5085,14 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.u2.un" value : uint16 #) when ^T : unativeint = (# "conv.ovf.u2.un" value : uint16 #) when ^T : byte = (# "conv.ovf.u2.un" value : uint16 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> uint16) (value)) - [] [] let inline char (value: ^T) = - (^T : (static member op_Explicit: ^T -> char) (value)) + OpExplicitDynamic<(^T), char> value when ^T : string = (System.Char.Parse(castToString value)) when ^T : float = (# "conv.ovf.u2" value : char #) when ^T : float32 = (# "conv.ovf.u2" value : char #) @@ -4516,11 +5107,14 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.u2.un" value : char #) when ^T : unativeint = (# "conv.ovf.u2.un" value : char #) when ^T : byte = (# "conv.ovf.u2.un" value : char #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> char) (value)) - [] [] let inline int16 (value: ^T) = - (^T : (static member op_Explicit: ^T -> int16) (value)) + OpExplicitDynamic<(^T), int16> value when ^T : string = ParseInt16 (castToString value) when ^T : float = (# "conv.ovf.i2" value : int16 #) when ^T : float32 = (# "conv.ovf.i2" value : int16 #) @@ -4535,11 +5129,14 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.i2.un" value : int16 #) when ^T : unativeint = (# "conv.ovf.i2.un" value : int16 #) when ^T : byte = (# "conv.ovf.i2.un" value : int16 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> int16) (value)) - [] [] let inline uint32 (value: ^T) = - (^T : (static member op_Explicit: ^T -> uint32) (value)) + OpExplicitDynamic<(^T), uint32> value when ^T : string = ParseUInt32 (castToString value) when ^T : float = (# "conv.ovf.u4" value : uint32 #) when ^T : float32 = (# "conv.ovf.u4" value : uint32 #) @@ -4554,11 +5151,14 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.u4.un" value : uint32 #) when ^T : unativeint = (# "conv.ovf.u4.un" value : uint32 #) when ^T : byte = (# "conv.ovf.u4.un" value : uint32 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> uint32) (value)) - [] [] let inline int32 (value: ^T) = - (^T : (static member op_Explicit: ^T -> int32) (value)) + OpExplicitDynamic<(^T), int32> value when ^T : string = ParseInt32 (castToString value) when ^T : float = (# "conv.ovf.i4" value : int32 #) when ^T : float32 = (# "conv.ovf.i4" value : int32 #) @@ -4573,15 +5173,17 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.i4.un" value : int32 #) when ^T : unativeint = (# "conv.ovf.i4.un" value : int32 #) when ^T : byte = (# "conv.ovf.i4.un" value : int32 #) - + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> int32) (value)) [] let inline int value = int32 value - [] [] let inline uint64 (value: ^T) = - (^T : (static member op_Explicit: ^T -> uint64) (value)) + OpExplicitDynamic<(^T), uint64> value when ^T : string = ParseUInt64 (castToString value) when ^T : float = (# "conv.ovf.u8" value : uint64 #) when ^T : float32 = (# "conv.ovf.u8" value : uint64 #) @@ -4596,11 +5198,14 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.u8.un" value : uint64 #) when ^T : unativeint = (# "conv.ovf.u8.un" value : uint64 #) when ^T : byte = (# "conv.ovf.u8.un" value : uint64 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> uint64) (value)) - [] [] let inline int64 (value: ^T) = - (^T : (static member op_Explicit: ^T -> int64) (value)) + OpExplicitDynamic<(^T), int64> value when ^T : string = ParseInt64 (castToString value) when ^T : float = (# "conv.ovf.i8" value : int64 #) when ^T : float32 = (# "conv.ovf.i8" value : int64 #) @@ -4615,11 +5220,14 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.i8.un" value : int64 #) when ^T : unativeint = (# "conv.ovf.i8.un" value : int64 #) when ^T : byte = (# "conv.ovf.i8.un" value : int64 #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> int64) (value)) - [] [] let inline unativeint (value: ^T) = - (^T : (static member op_Explicit: ^T -> unativeint) (value)) + OpExplicitDynamic<(^T), unativeint> value when ^T : string = ParseUIntPtr (castToString value) when ^T : float = (# "conv.ovf.u" value : unativeint #) when ^T : float32 = (# "conv.ovf.u" value : unativeint #) @@ -4634,11 +5242,14 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.u.un" value : unativeint #) when ^T : unativeint = (# "conv.ovf.u.un" value : unativeint #) when ^T : byte = (# "conv.ovf.u.un" value : unativeint #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> unativeint) (value)) - [] [] let inline nativeint (value: ^T) = - (^T : (static member op_Explicit: ^T -> nativeint) (value)) + OpExplicitDynamic<(^T), nativeint> value when ^T : string = ParseIntPtr (castToString value) when ^T : float = (# "conv.ovf.i" value : nativeint #) when ^T : float32 = (# "conv.ovf.i" value : nativeint #) @@ -4653,6 +5264,10 @@ namespace Microsoft.FSharp.Core when ^T : char = (# "conv.ovf.i.un" value : nativeint #) when ^T : unativeint = (# "conv.ovf.i.un" value : nativeint #) when ^T : byte = (# "conv.ovf.i.un" value : nativeint #) + // According to the somewhat subtle rules of static optimizations, + // this condition is used whenever ^T is resolved to a nominal type or witnesses are available + // That is, not in the generic implementation of '*' + when ^T : ^T = (^T : (static member op_Explicit: ^T -> nativeint) (value)) module OperatorIntrinsics = @@ -5179,7 +5794,6 @@ namespace Microsoft.FSharp.Core if len <= 0 then String.Empty else source.Substring(start, len) - [] let inline absImpl (x: ^T) : ^T = (^T: (static member Abs : ^T -> ^T) (x)) when ^T : int32 = let x : int32 = retype x in System.Math.Abs(x) @@ -5187,70 +5801,62 @@ namespace Microsoft.FSharp.Core when ^T : float32 = let x : float32 = retype x in System.Math.Abs(x) when ^T : int64 = let x : int64 = retype x in System.Math.Abs(x) when ^T : nativeint = - let x : nativeint = retype x in - if x >= 0n then x else - let res = -x in - if res < 0n then raise (System.OverflowException(ErrorStrings.NoNegateMinValueString)) - res + (let x : nativeint = retype x + if x >= 0n then + x + else + let res = -x + if res < 0n then raise (System.OverflowException(ErrorStrings.NoNegateMinValueString)) + res) when ^T : int16 = let x : int16 = retype x in System.Math.Abs(x) when ^T : sbyte = let x : sbyte = retype x in System.Math.Abs(x) when ^T : decimal = System.Math.Abs(retype x : decimal) - [] let inline acosImpl(x: ^T) : ^T = (^T: (static member Acos : ^T -> ^T) (x)) when ^T : float = System.Math.Acos(retype x) when ^T : float32 = System.Math.Acos(toFloat (retype x)) |> toFloat32 - [] let inline asinImpl(x: ^T) : ^T = (^T: (static member Asin : ^T -> ^T) (x)) when ^T : float = System.Math.Asin(retype x) when ^T : float32 = System.Math.Asin(toFloat (retype x)) |> toFloat32 - [] let inline atanImpl(x: ^T) : ^T = (^T: (static member Atan : ^T -> ^T) (x)) when ^T : float = System.Math.Atan(retype x) when ^T : float32 = System.Math.Atan(toFloat (retype x)) |> toFloat32 - [] let inline atan2Impl(x: ^T) (y: ^T) : 'U = (^T: (static member Atan2 : ^T * ^T -> 'U) (x,y)) when ^T : float = System.Math.Atan2(retype x, retype y) when ^T : float32 = System.Math.Atan2(toFloat (retype x), toFloat(retype y)) |> toFloat32 - [] let inline ceilImpl(x: ^T) : ^T = (^T: (static member Ceiling : ^T -> ^T) (x)) when ^T : float = System.Math.Ceiling(retype x : float) when ^T : float32 = System.Math.Ceiling(toFloat (retype x)) |> toFloat32 - [] let inline expImpl(x: ^T) : ^T = (^T: (static member Exp : ^T -> ^T) (x)) when ^T : float = System.Math.Exp(retype x) when ^T : float32 = System.Math.Exp(toFloat (retype x)) |> toFloat32 - [] let inline floorImpl (x: ^T) : ^T = (^T: (static member Floor : ^T -> ^T) (x)) when ^T : float = System.Math.Floor(retype x : float) when ^T : float32 = System.Math.Floor(toFloat (retype x)) |> toFloat32 - [] let inline truncateImpl (x: ^T) : ^T = (^T: (static member Truncate : ^T -> ^T) (x)) when ^T : float = System.Math.Truncate(retype x : float) when ^T : float32 = System.Math.Truncate(toFloat (retype x)) |> toFloat32 - [] let inline roundImpl (x: ^T) : ^T = (^T: (static member Round : ^T -> ^T) (x)) when ^T : float = System.Math.Round(retype x : float) when ^T : float32 = System.Math.Round(toFloat (retype x)) |> toFloat32 - [] let inline signImpl (x: ^T) : int = (^T: (member Sign : int) (x)) when ^T : int32 = System.Math.Sign(retype x : int32) @@ -5262,79 +5868,56 @@ namespace Microsoft.FSharp.Core when ^T : float32 = System.Math.Sign(toFloat (retype x)) when ^T : decimal = System.Math.Sign(retype x : decimal) - [] let inline logImpl(x: ^T) : ^T = (^T: (static member Log : ^T -> ^T) (x)) when ^T : float = System.Math.Log(retype x) when ^T : float32 = System.Math.Log(toFloat (retype x)) |> toFloat32 - [] let inline log10Impl(x: ^T) : ^T = (^T: (static member Log10 : ^T -> ^T) (x)) when ^T : float = System.Math.Log10(retype x) when ^T : float32 = System.Math.Log10(toFloat (retype x)) |> toFloat32 - [] let inline sqrtImpl(x: ^T) : ^U = (^T: (static member Sqrt : ^T -> ^U) (x)) when ^T : float = System.Math.Sqrt(retype x : float) when ^T : float32 = System.Math.Sqrt(toFloat (retype x)) |> toFloat32 - [] let inline cosImpl(x: ^T) : ^T = (^T: (static member Cos : ^T -> ^T) (x)) when ^T : float = System.Math.Cos(retype x) when ^T : float32 = System.Math.Cos(toFloat (retype x)) |> toFloat32 - [] let inline coshImpl(x: ^T) : ^T = (^T: (static member Cosh : ^T -> ^T) (x)) when ^T : float = System.Math.Cosh(retype x) when ^T : float32 = System.Math.Cosh(toFloat (retype x)) |> toFloat32 - [] let inline sinImpl(x: ^T) : ^T = (^T: (static member Sin : ^T -> ^T) (x)) when ^T : float = System.Math.Sin(retype x) when ^T : float32 = System.Math.Sin(toFloat (retype x)) |> toFloat32 - [] let inline sinhImpl(x: ^T) : ^T = (^T: (static member Sinh : ^T -> ^T) (x)) when ^T : float = System.Math.Sinh(retype x) when ^T : float32 = System.Math.Sinh(toFloat (retype x)) |> toFloat32 - [] let inline tanImpl(x: ^T) : ^T = (^T: (static member Tan : ^T -> ^T) (x)) when ^T : float = System.Math.Tan(retype x) when ^T : float32 = System.Math.Tan(toFloat (retype x)) |> toFloat32 - [] let inline tanhImpl(x: ^T) : ^T = (^T: (static member Tanh : ^T -> ^T) (x)) when ^T : float = System.Math.Tanh(retype x) when ^T : float32 = System.Math.Tanh(toFloat (retype x)) |> toFloat32 - [] let inline powImpl (x: ^T) (y: ^U) : ^T = (^T: (static member Pow : ^T * ^U -> ^T) (x,y)) when ^T : float = System.Math.Pow((retype x : float), (retype y: float)) when ^T : float32 = System.Math.Pow(toFloat (retype x), toFloat(retype y)) |> toFloat32 - [] - let UnaryDynamicImpl nm : ('T -> 'U) = - let aty = typeof<'T> - let minfo = aty.GetMethod(nm, [| aty |]) - (fun x -> unboxPrim<_>(minfo.Invoke(null,[| box x|]))) - - let BinaryDynamicImpl nm : ('T -> 'U -> 'V) = - let aty = typeof<'T> - let bty = typeof<'U> - let minfo = aty.GetMethod(nm,[| aty;bty |]) - (fun x y -> unboxPrim<_>(minfo.Invoke(null,[| box x; box y|]))) - - [] type AbsDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5349,7 +5932,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Abs" static member Result : ('T -> 'T) = result - [] type AcosDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5358,7 +5940,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Acos" static member Result : ('T -> 'T) = result - [] type AsinDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5367,7 +5948,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Asin" static member Result : ('T -> 'T) = result - [] type AtanDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5376,7 +5956,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Atan" static member Result : ('T -> 'T) = result - [] type Atan2DynamicImplTable<'T,'U>() = static let result : ('T -> 'T -> 'U) = let aty = typeof<'T> @@ -5385,7 +5964,6 @@ namespace Microsoft.FSharp.Core else BinaryDynamicImpl "Atan2" static member Result : ('T -> 'T -> 'U) = result - [] type CeilingDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5394,7 +5972,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Ceiling" static member Result : ('T -> 'T) = result - [] type ExpDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5403,7 +5980,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Exp" static member Result : ('T -> 'T) = result - [] type FloorDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5412,7 +5988,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Floor" static member Result : ('T -> 'T) = result - [] type TruncateDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5421,7 +5996,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Truncate" static member Result : ('T -> 'T) = result - [] type RoundDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5430,7 +6004,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Round" static member Result : ('T -> 'T) = result - [] type SignDynamicImplTable<'T>() = static let result : ('T -> int) = let aty = typeof<'T> @@ -5445,7 +6018,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Sign" static member Result : ('T -> int) = result - [] type LogDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5454,7 +6026,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Log" static member Result : ('T -> 'T) = result - [] type Log10DynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5463,7 +6034,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Log10" static member Result : ('T -> 'T) = result - [] type SqrtDynamicImplTable<'T,'U>() = static let result : ('T -> 'U) = let aty = typeof<'T> @@ -5472,7 +6042,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Sqrt" static member Result : ('T -> 'U) = result - [] type CosDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5481,7 +6050,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Cos" static member Result : ('T -> 'T) = result - [] type CoshDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5490,7 +6058,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Cosh" static member Result : ('T -> 'T) = result - [] type SinDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5499,7 +6066,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Sin" static member Result : ('T -> 'T) = result - [] type SinhDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5508,7 +6074,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Sinh" static member Result : ('T -> 'T) = result - [] type TanDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5517,7 +6082,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Tan" static member Result : ('T -> 'T) = result - [] type TanhDynamicImplTable<'T>() = static let result : ('T -> 'T) = let aty = typeof<'T> @@ -5526,7 +6090,6 @@ namespace Microsoft.FSharp.Core else UnaryDynamicImpl "Tanh" static member Result : ('T -> 'T) = result - [] type PowDynamicImplTable<'T,'U>() = static let result : ('T -> 'U -> 'T) = let aty = typeof<'T> diff --git a/src/fsharp/FSharp.Core/prim-types.fsi b/src/fsharp/FSharp.Core/prim-types.fsi index c977af45417..85b7dc12e25 100644 --- a/src/fsharp/FSharp.Core/prim-types.fsi +++ b/src/fsharp/FSharp.Core/prim-types.fsi @@ -714,6 +714,8 @@ namespace Microsoft.FSharp.Core /// NoDynamicInvocationAttribute new : unit -> NoDynamicInvocationAttribute + new : isLegacy: bool -> NoDynamicInvocationAttribute + /// This attribute is used to indicate that references to the elements of a module, record or union /// type require explicit qualified access. [] @@ -801,7 +803,7 @@ namespace Microsoft.FSharp.Core type int64<[] 'Measure> = int64 /// Represents a managed pointer in F# code. -#if BUILDING_WITH_LKG || BUILD_FROM_SOURCE +#if BUILDING_WITH_LKG [] #else [] @@ -812,7 +814,7 @@ namespace Microsoft.FSharp.Core type byref<'T> = (# "!0&" #) /// Represents the types of byrefs in F# 4.5+ -#if BUILDING_WITH_LKG || BUILD_FROM_SOURCE +#if BUILDING_WITH_LKG [] #else [] @@ -820,7 +822,7 @@ namespace Microsoft.FSharp.Core module ByRefKinds = /// Represents a byref that can be written -#if BUILDING_WITH_LKG || BUILD_FROM_SOURCE +#if BUILDING_WITH_LKG [] #else [] @@ -828,7 +830,7 @@ namespace Microsoft.FSharp.Core type Out /// Represents a byref that can be read -#if BUILDING_WITH_LKG || BUILD_FROM_SOURCE +#if BUILDING_WITH_LKG [] #else [] @@ -836,7 +838,7 @@ namespace Microsoft.FSharp.Core type In /// Represents a byref that can be both read and written -#if BUILDING_WITH_LKG || BUILD_FROM_SOURCE +#if BUILDING_WITH_LKG [] #else [] @@ -1063,30 +1065,106 @@ namespace Microsoft.FSharp.Core [] val GenericOneDynamic : unit -> 'T - /// A compiler intrinsic that implements dynamic invocations to the '+' operator. + /// A compiler intrinsic that implements dynamic invocations to the '+' operator when used in quotations. [] val AdditionDynamic : x:'T1 -> y:'T2 -> 'U - /// A compiler intrinsic that implements dynamic invocations to the checked '+' operator. + /// A compiler intrinsic that implements dynamic invocations to the '-' operator when used in quotations. [] - val CheckedAdditionDynamic : x:'T1 -> y:'T2 -> 'U + val SubtractionDynamic : x:'T1 -> y:'T2 -> 'U - /// A compiler intrinsic that implements dynamic invocations to the '*' operator. + /// A compiler intrinsic that implements dynamic invocations to the '*' operator when used in quotations. [] val MultiplyDynamic : x:'T1 -> y:'T2 -> 'U - /// A compiler intrinsic that implements dynamic invocations to the checked '*' operator. + /// A compiler intrinsic that implements dynamic invocations to the '/' operator when used in quotations. + [] + val DivisionDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations to the unary '-' operator when used in quotations. + [] + val UnaryNegationDynamic : value:'T -> 'U + + /// A compiler intrinsic that implements dynamic invocations to the '%' operator when used in quotations. + [] + val ModulusDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations to the checked '+' operator when used in quotations. + [] + val CheckedAdditionDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations to the checked '-' operator when used in quotations. + [] + val CheckedSubtractionDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations to the checked '*' operator when used in quotations. [] val CheckedMultiplyDynamic : x:'T1 -> y:'T2 -> 'U - /// A compiler intrinsic that implements dynamic invocations for the DivideByInt primitive. + /// A compiler intrinsic that implements dynamic invocations to the checked unary '-' operator when used in quotations. + [] + val CheckedUnaryNegationDynamic : value:'T -> 'U + + /// A compiler intrinsic that implements dynamic invocations to the '<<<' operator when used in quotations. + [] + val OpLeftShiftDynamic : value:'T1 -> shift:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations to the '>>>' operator when used in quotations. + [] + val OpRightShiftDynamic : value:'T1 -> shift:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations to the '&&&' operator when used in quotations. + [] + val OpBitwiseAndDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations to the '|||' operator when used in quotations. + [] + val OpBitwiseOrDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations related to the '^^^' operator when used in quotations. + [] + val OpBitwiseExclusiveOrDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations related to the '~~~' operator when used in quotations. + [] + val OpLogicalNotDynamic : value:'T1 -> 'U + + /// A compiler intrinsic that implements dynamic invocations related to conversion operators when used in quotations. + [] + val OpExplicitDynamic : value:'T1 -> 'U + + /// A compiler intrinsic that implements dynamic invocations related to the '<' operator when used in quotations. + [] + val OpLessThanDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations related to the '>' operator when used in quotations. + [] + val OpGreaterThanDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations related to the '<=' operator when used in quotations. + [] + val OpLessThanOrEqualDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations related to the '>=' operator when used in quotations. + [] + val OpGreaterThanOrEqualDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations related to the '=' operator when used in quotations. + [] + val OpEqualityDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations related to the '=' operator when used in quotations. + [] + val OpInequalityDynamic : x:'T1 -> y:'T2 -> 'U + + /// A compiler intrinsic that implements dynamic invocations for the DivideByInt primitive when used in quotations. [] val DivideByIntDynamic : x:'T -> y:int -> 'T /// Resolves to the zero value for any primitive numeric type or any type with a static member called 'Zero' val inline GenericZero< ^T > : ^T when ^T : (static member Zero : ^T) - /// Resolves to the value 'one' for any primitive numeric type or any type with a static member called 'One' + /// Resolves to the value one for any primitive numeric type or any type with a static member called One val inline GenericOne< ^T > : ^T when ^T : (static member One : ^T) val internal anyToStringShowingNull : 'T -> string @@ -1097,6 +1175,1308 @@ namespace Microsoft.FSharp.Core /// The division result. val inline DivideByInt< ^T > : x:^T -> y:int -> ^T when ^T : (static member DivideByInt : ^T * int -> ^T) +#if !BUILDING_WITH_LKG + [] + /// Representative witnesses for traits solved by the F# compiler + type BuiltInWitnesses = + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: int32 * y: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: float * y: float -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: float32 * y: float32 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: int64 * y: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: uint64 * y: uint64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: uint32 * y: uint32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: nativeint * y: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: unativeint * y: unativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: int16 * y: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: uint16 * y: uint16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: char * y: char -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: sbyte * y: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: byte * y: byte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: string * y: string -> string + + /// A representative witness for traits solved by the F# compiler + static member inline op_Addition: x: decimal * y: decimal -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: int32 * y: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: float * y: float -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: float32 * y: float32 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: int64 * y: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: uint64 * y: uint64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: uint32 * y: uint32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: nativeint * y: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: unativeint * y: unativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: int16 * y: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: uint16 * y: uint16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: sbyte * y: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: byte * y: byte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Multiply: x: decimal * y: decimal -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_UnaryNegation: value: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_UnaryNegation: value: float -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_UnaryNegation: value: float32 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_UnaryNegation: value: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_UnaryNegation: value: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_UnaryNegation: value: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_UnaryNegation: value: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_UnaryNegation: value: decimal -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: int32 * y: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: float * y: float -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: float32 * y: float32 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: int64 * y: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: uint64 * y: uint64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: uint32 * y: uint32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: nativeint * y: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: unativeint * y: unativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: int16 * y: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: uint16 * y: uint16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: sbyte * y: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: byte * y: byte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Subtraction: x: decimal * y: decimal -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: int32 * y: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: float * y: float -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: float32 * y: float32 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: int64 * y: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: uint64 * y: uint64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: uint32 * y: uint32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: nativeint * y: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: unativeint * y: unativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: int16 * y: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: uint16 * y: uint16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: sbyte * y: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: byte * y: byte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Division: x: decimal * y: decimal -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: int32 * y: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: float * y: float -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: float32 * y: float32 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: int64 * y: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: uint64 * y: uint64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: uint32 * y: uint32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: nativeint * y: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: unativeint * y: unativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: int16 * y: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: uint16 * y: uint16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: sbyte * y: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: byte * y: byte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Modulus: x: decimal * y: decimal -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_LeftShift: value: int32 * shift: int -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LeftShift: value: uint32 * shift: int -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LeftShift: value: int64 * shift: int -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LeftShift: value: uint64 * shift: int -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LeftShift: value: nativeint * shift: int -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_LeftShift: value: unativeint * shift: int -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_LeftShift: value: int16 * shift: int -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LeftShift: value: uint16 * shift: int -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LeftShift: value: sbyte * shift: int -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_LeftShift: value: byte * shift: int -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_RightShift: value: byte * shift: int -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_RightShift: value: sbyte * shift: int -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_RightShift: value: int16 * shift: int -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_RightShift: value: uint16 * shift: int -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_RightShift: value: int32 * shift: int -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_RightShift: value: uint32 * shift: int -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_RightShift: value: int64 * shift: int -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_RightShift: value: uint64 * shift: int -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_RightShift: value: nativeint * shift: int -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_RightShift: value: unativeint * shift: int -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseAnd: x: int32 * y: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseAnd: x: int64 * y: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseAnd: x: uint64 * y: uint64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseAnd: x: uint32 * y: uint32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseAnd: x: int16 * y: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseAnd: x: uint16 * y: uint16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseAnd: x: nativeint * y: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseAnd: x: unativeint * y: unativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseAnd: x: sbyte * y: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseAnd: x: byte * y: byte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseOr: x: int32 * y: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseOr: x: int64 * y: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseOr: x: uint64 * y: uint64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseOr: x: uint32 * y: uint32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseOr: x: int16 * y: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseOr: x: uint16 * y: uint16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseOr: x: nativeint * y: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseOr: x: unativeint * y: unativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseOr: x: sbyte * y: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_BitwiseOr: x: byte * y: byte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_ExclusiveOr: x: int32 * y: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_ExclusiveOr: x: int64 * y: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_ExclusiveOr: x: uint64 * y: uint64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_ExclusiveOr: x: uint32 * y: uint32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_ExclusiveOr: x: int16 * y: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_ExclusiveOr: x: uint16 * y: uint16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_ExclusiveOr: x: nativeint * y: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_ExclusiveOr: x: unativeint * y: unativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_ExclusiveOr: x: sbyte * y: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_ExclusiveOr: x: byte * y: byte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_LogicalNot: value: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LogicalNot: value: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LogicalNot: value: uint64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LogicalNot: value: uint32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LogicalNot: value: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_LogicalNot: value: unativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_LogicalNot: value: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LogicalNot: value: uint16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_LogicalNot: value: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_LogicalNot: value: byte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> byte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> sbyte + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> uint16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> int16 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> uint32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> int32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> uint64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> int64 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: decimal -> float + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: decimal -> decimal + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> unativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> nativeint + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: string -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: float32 -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int64 -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int32 -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: int16 -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: nativeint -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: sbyte -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint64 -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint32 -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: uint16 -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: char -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: unativeint -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_Explicit: value: byte -> char + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: bool * y: bool -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: sbyte * y: sbyte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: int16 * y: int16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: int32 * y: int32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: int64 * y: int64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: byte * y: byte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: uint16 * y: uint16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: uint32 * y: uint32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: uint64 * y: uint64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: unativeint * y: unativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: nativeint * y: nativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: float * y: float -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: float32 * y: float32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: char * y: char -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: decimal * y: decimal -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThan: x: string * y: string -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: bool * y: bool -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: sbyte * y: sbyte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: int16 * y: int16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: int32 * y: int32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: int64 * y: int64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: nativeint * y: nativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: byte * y: byte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: uint16 * y: uint16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: uint32 * y: uint32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: uint64 * y: uint64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: unativeint * y: unativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: float * y: float -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: float32 * y: float32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: char * y: char -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: decimal * y: decimal -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThan: x: string * y: string -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: bool * y: bool -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: sbyte * y: sbyte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: int16 * y: int16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: int32 * y: int32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: int64 * y: int64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: nativeint * y: nativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: byte * y: byte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: uint16 * y: uint16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: uint32 * y: uint32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: uint64 * y: uint64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: unativeint * y: unativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: float * y: float -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: float32 * y: float32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: char * y: char -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: decimal * y: decimal -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_LessThanOrEqual: x: string * y: string -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: bool * y: bool -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: sbyte * y: sbyte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: int16 * y: int16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: int32 * y: int32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: int64 * y: int64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: nativeint * y: nativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: byte * y: byte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: uint16 * y: uint16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: uint32 * y: uint32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: uint64 * y: uint64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: unativeint * y: unativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: float * y: float -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: float32 * y: float32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: char * y: char -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: decimal * y: decimal -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_GreaterThanOrEqual: x: string * y: string -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: bool * y: bool -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: sbyte * y: sbyte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: int16 * y: int16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: int32 * y: int32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: int64 * y: int64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: byte * y: byte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: uint16 * y: uint16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: uint32 * y: uint32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: uint64 * y: uint64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: float * y: float -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: float32 * y: float32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: char * y: char -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: nativeint * y: nativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: unativeint * y: unativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: string * y: string -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Equality: x: decimal * y: decimal -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: bool * y: bool -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: sbyte * y: sbyte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: int16 * y: int16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: int32 * y: int32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: int64 * y: int64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: byte * y: byte -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: uint16 * y: uint16 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: uint32 * y: uint32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: uint64 * y: uint64 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: float * y: float -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: float32 * y: float32 -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: char * y: char -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: nativeint * y: nativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: unativeint * y: unativeint -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: string * y: string -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline op_Inequality: x: decimal * y: decimal -> bool + + /// A representative witness for traits solved by the F# compiler + static member inline DivideByInt: x: float * y: int -> float + + /// A representative witness for traits solved by the F# compiler + static member inline DivideByInt: x: float32 * y: int -> float32 + + /// A representative witness for traits solved by the F# compiler + static member inline DivideByInt: x: decimal * y: int -> decimal +#endif + /// For compiler use only module (* internal *) ErrorStrings = @@ -2743,6 +4123,7 @@ namespace Microsoft.FSharp.Core /// input types the operation requires an appropriate static conversion method on the input type. /// The input value. /// The converted char. + [] [] val inline char : value:^T -> char when ^T : (static member op_Explicit : ^T -> char) and default ^T : int @@ -3181,14 +4562,14 @@ namespace Microsoft.FSharp.Core /// Overloaded unary negation (checks for overflow) /// The input value. /// The negated value. - [] + [] val inline ( ~- ) : value:^T -> ^T when ^T : (static member ( ~- ) : ^T -> ^T) and default ^T : int /// Overloaded subtraction operator (checks for overflow) /// The first value. /// The second value. /// The first value minus the second value. - [] + [] val inline ( - ) : x:^T1 -> y:^T2 -> ^T3 when (^T1 or ^T2) : (static member ( - ) : ^T1 * ^T2 -> ^T3) and default ^T2 : ^T3 and default ^T3 : ^T1 and default ^T3 : ^T2 and default ^T1 : ^T3 and default ^T1 : ^T2 and default ^T1 : int /// Overloaded addition operator (checks for overflow) @@ -3201,7 +4582,7 @@ namespace Microsoft.FSharp.Core /// The first value. /// The second value. /// The product of the two input values. - [] + [] val inline ( * ) : x:^T1 -> y:^T2 -> ^T3 when (^T1 or ^T2) : (static member ( * ) : ^T1 * ^T2 -> ^T3) and default ^T2 : ^T3 and default ^T3 : ^T1 and default ^T3 : ^T2 and default ^T1 : ^T3 and default ^T1 : ^T2 and default ^T1 : int /// Converts the argument to byte. This is a direct, checked conversion for all @@ -3210,7 +4591,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted byte - [] + [] [] val inline byte : value:^T -> byte when ^T : (static member op_Explicit : ^T -> byte) and default ^T : int @@ -3220,7 +4601,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted sbyte - [] + [] [] val inline sbyte : value:^T -> sbyte when ^T : (static member op_Explicit : ^T -> sbyte) and default ^T : int @@ -3230,7 +4611,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted int16 - [] + [] [] val inline int16 : value:^T -> int16 when ^T : (static member op_Explicit : ^T -> int16) and default ^T : int @@ -3240,7 +4621,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted uint16 - [] + [] [] val inline uint16 : value:^T -> uint16 when ^T : (static member op_Explicit : ^T -> uint16) and default ^T : int @@ -3250,7 +4631,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted int - [] + [] [] val inline int : value:^T -> int when ^T : (static member op_Explicit : ^T -> int) and default ^T : int @@ -3260,7 +4641,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted int32 - [] + [] [] val inline int32 : value:^T -> int32 when ^T : (static member op_Explicit : ^T -> int32) and default ^T : int @@ -3270,7 +4651,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted uint32 - [] + [] [] val inline uint32 : value:^T -> uint32 when ^T : (static member op_Explicit : ^T -> uint32) and default ^T : int @@ -3280,7 +4661,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted int64 - [] + [] [] val inline int64 : value:^T -> int64 when ^T : (static member op_Explicit : ^T -> int64) and default ^T : int @@ -3290,7 +4671,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted uint64 - [] + [] [] val inline uint64 : value:^T -> uint64 when ^T : (static member op_Explicit : ^T -> uint64) and default ^T : int @@ -3299,7 +4680,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted nativeint - [] + [] [] val inline nativeint : value:^T -> nativeint when ^T : (static member op_Explicit : ^T -> nativeint) and default ^T : int @@ -3308,7 +4689,7 @@ namespace Microsoft.FSharp.Core /// static conversion method on the input type. /// The input value. /// The converted unativeint - [] + [] [] val inline unativeint : value:^T -> unativeint when ^T : (static member op_Explicit : ^T -> unativeint) and default ^T : int @@ -3318,7 +4699,7 @@ namespace Microsoft.FSharp.Core /// appropriate static conversion method on the input type. /// The input value. /// The converted char - [] + [] [] val inline char : value:^T -> char when ^T : (static member op_Explicit : ^T -> char) and default ^T : int diff --git a/src/fsharp/FSharp.Core/quotations.fs b/src/fsharp/FSharp.Core/quotations.fs index 55694d22ad9..5272732f852 100644 --- a/src/fsharp/FSharp.Core/quotations.fs +++ b/src/fsharp/FSharp.Core/quotations.fs @@ -175,6 +175,10 @@ and | NewObjectOp of ConstructorInfo | InstanceMethodCallOp of MethodInfo | StaticMethodCallOp of MethodInfo + /// A new Call node type in F# 5.0, storing extra information about witnesses + | InstanceMethodCallWOp of MethodInfo * MethodInfo * int + /// A new Call node type in F# 5.0, storing extra information about witnesses + | StaticMethodCallWOp of MethodInfo * MethodInfo * int | CoerceOp of Type | NewArrayOp of Type | NewDelegateOp of Type @@ -193,7 +197,7 @@ and | WithValueOp of obj * Type | DefaultValueOp of Type -and [] +and [] Expr(term:Tree, attribs:Expr list) = member x.Tree = term member x.CustomAttributes = attribs @@ -205,6 +209,27 @@ and [] match t1, t2 with // We special-case ValueOp to ensure that ValueWithName = Value | CombTerm(ValueOp(v1, ty1, _), []), CombTerm(ValueOp(v2, ty2, _), []) -> (v1 = v2) && (ty1 = ty2) + + // We strip off InstanceMethodCallWOp to ensure that CallWithWitness = Call + | CombTerm(InstanceMethodCallWOp(minfo1, _minfoW1, nWitnesses1), args1), _ -> + let argsWithoutWitnesses1 = List.skip nWitnesses1 args1 + eq (CombTerm(InstanceMethodCallOp(minfo1), argsWithoutWitnesses1)) t2 + + // We strip off InstanceMethodCallWOp to ensure that CallWithWitness = Call + | _, CombTerm(InstanceMethodCallWOp(minfo2, _minfoW2, nWitnesses2), args2) -> + let argsWithoutWitnesses2 = List.skip nWitnesses2 args2 + eq t1 (CombTerm(InstanceMethodCallOp(minfo2), argsWithoutWitnesses2)) + + // We strip off StaticMethodCallWOp to ensure that CallWithWitness = Call + | CombTerm(StaticMethodCallWOp(minfo1, _minfoW1, nWitnesses1), args1), _ -> + let argsWithoutWitnesses1 = List.skip nWitnesses1 args1 + eq (CombTerm(StaticMethodCallOp(minfo1), argsWithoutWitnesses1)) t2 + + // We strip off StaticMethodCallWOp to ensure that CallWithWitness = Call + | _, CombTerm(StaticMethodCallWOp(minfo2, _minfoW2, nWitnesses2), args2) -> + let argsWithoutWitnesses2 = List.skip nWitnesses2 args2 + eq t1 (CombTerm(StaticMethodCallOp(minfo2), argsWithoutWitnesses2)) + | CombTerm(c1, es1), CombTerm(c2, es2) -> c1 = c2 && es1.Length = es2.Length && (es1 = es2) | VarTerm v1, VarTerm v2 -> (v1 = v2) | LambdaTerm (v1, e1), LambdaTerm(v2, e2) -> (v1 = v2) && (e1 = e2) @@ -219,11 +244,13 @@ and [] override x.ToString() = x.ToString false member x.ToString full = - Microsoft.FSharp.Text.StructuredPrintfImpl.Display.layout_to_string Microsoft.FSharp.Text.StructuredPrintfImpl.FormatOptions.Default (x.GetLayout full) + Display.layout_to_string FormatOptions.Default (x.GetLayout(full)) + + member x.DebugText = x.ToString(false) member x.GetLayout long = - let expr (e:Expr ) = e.GetLayout long - let exprs (es:Expr list) = es |> List.map expr + let expr (e: Expr) = e.GetLayout(long) + let exprs (es: Expr list) = es |> List.map expr let parens ls = bracketL (commaListL ls) let pairL l1 l2 = bracketL (l1 ^^ sepL Literals.comma ^^ l2) let listL ls = squareBracketL (commaListL ls) @@ -237,7 +264,7 @@ and [] let (|E|) (e: Expr) = e.Tree let (|Lambda|_|) (E x) = match x with LambdaTerm(a, b) -> Some (a, b) | _ -> None let (|IteratedLambda|_|) (e: Expr) = qOneOrMoreRLinear (|Lambda|_|) e - let ucaseL (unionCase:UnionCaseInfo) = (if long then objL unionCase else wordL (tagUnionCase unionCase.Name)) + let ucaseL (unionCase: UnionCaseInfo) = (if long then objL unionCase else wordL (tagUnionCase unionCase.Name)) let minfoL (minfo: MethodInfo) = if long then objL minfo else wordL (tagMethod minfo.Name) let cinfoL (cinfo: ConstructorInfo) = if long then objL cinfo else wordL (tagMethod cinfo.DeclaringType.Name) let pinfoL (pinfo: PropertyInfo) = if long then objL pinfo else wordL (tagProperty pinfo.Name) @@ -261,17 +288,27 @@ and [] | CombTerm(ValueOp(v, _, Some nm), []) -> combL "ValueWithName" [objL v; wordL (tagLocal nm)] | CombTerm(ValueOp(v, _, None), []) -> combL "Value" [objL v] | CombTerm(WithValueOp(v, _), [defn]) -> combL "WithValue" [objL v; expr defn] - | CombTerm(InstanceMethodCallOp minfo, obj :: args) -> combL "Call" [someL obj; minfoL minfo; listL (exprs args)] - | CombTerm(StaticMethodCallOp minfo, args) -> combL "Call" [noneL; minfoL minfo; listL (exprs args)] - | CombTerm(InstancePropGetOp pinfo, (obj :: args)) -> combL "PropertyGet" [someL obj; pinfoL pinfo; listL (exprs args)] - | CombTerm(StaticPropGetOp pinfo, args) -> combL "PropertyGet" [noneL; pinfoL pinfo; listL (exprs args)] - | CombTerm(InstancePropSetOp pinfo, (obj :: args)) -> combL "PropertySet" [someL obj; pinfoL pinfo; listL (exprs args)] - | CombTerm(StaticPropSetOp pinfo, args) -> combL "PropertySet" [noneL; pinfoL pinfo; listL (exprs args)] - | CombTerm(InstanceFieldGetOp finfo, [obj]) -> combL "FieldGet" [someL obj; finfoL finfo] - | CombTerm(StaticFieldGetOp finfo, []) -> combL "FieldGet" [noneL; finfoL finfo] - | CombTerm(InstanceFieldSetOp finfo, [obj;v]) -> combL "FieldSet" [someL obj; finfoL finfo; expr v;] - | CombTerm(StaticFieldSetOp finfo, [v]) -> combL "FieldSet" [noneL; finfoL finfo; expr v;] - | CombTerm(CoerceOp ty, [arg]) -> combL "Coerce" [ expr arg; typeL ty] + | CombTerm(InstanceMethodCallOp(minfo), obj::args) -> combL "Call" [someL obj; minfoL minfo; listL (exprs args)] + | CombTerm(StaticMethodCallOp(minfo), args) -> combL "Call" [noneL; minfoL minfo; listL (exprs args)] + + | CombTerm(InstanceMethodCallWOp(minfo, _minfoW, nWitnesses), args) -> + let argsWithoutWitnesses = List.skip nWitnesses args + match argsWithoutWitnesses with + | objArg :: argsWithoutObj -> combL "Call" [someL objArg; minfoL minfo; listL (exprs argsWithoutObj)] + | _ -> failwithf "Unexpected term in layout %A" x.Tree + + | CombTerm(StaticMethodCallWOp(minfo, _minfoW, nWitnesses), args) -> + combL "Call" [noneL; minfoL minfo; listL (exprs (List.skip nWitnesses args))] + + | CombTerm(InstancePropGetOp(pinfo), (obj::args)) -> combL "PropertyGet" [someL obj; pinfoL pinfo; listL (exprs args)] + | CombTerm(StaticPropGetOp(pinfo), args) -> combL "PropertyGet" [noneL; pinfoL pinfo; listL (exprs args)] + | CombTerm(InstancePropSetOp(pinfo), (obj::args)) -> combL "PropertySet" [someL obj; pinfoL pinfo; listL (exprs args)] + | CombTerm(StaticPropSetOp(pinfo), args) -> combL "PropertySet" [noneL; pinfoL pinfo; listL (exprs args)] + | CombTerm(InstanceFieldGetOp(finfo), [obj]) -> combL "FieldGet" [someL obj; finfoL finfo] + | CombTerm(StaticFieldGetOp(finfo), []) -> combL "FieldGet" [noneL; finfoL finfo] + | CombTerm(InstanceFieldSetOp(finfo), [obj;v]) -> combL "FieldSet" [someL obj; finfoL finfo; expr v;] + | CombTerm(StaticFieldSetOp(finfo), [v]) -> combL "FieldSet" [noneL; finfoL finfo; expr v;] + | CombTerm(CoerceOp(ty), [arg]) -> combL "Coerce" [ expr arg; typeL ty] | CombTerm(NewObjectOp cinfo, args) -> combL "NewObject" ([ cinfoL cinfo ] @ exprs args) | CombTerm(DefaultValueOp ty, args) -> combL "DefaultValue" ([ typeL ty ] @ exprs args) | CombTerm(NewArrayOp ty, args) -> combL "NewArray" ([ typeL ty ] @ exprs args) @@ -302,8 +339,6 @@ and [] | CombTerm(QuoteOp _, args) -> combL "Quote" (exprs args) | _ -> failwithf "Unexpected term in layout %A" x.Tree - - and [] Expr<'T>(term:Tree, attribs) = inherit Expr(term, attribs) @@ -344,7 +379,7 @@ module Patterns = let ES ts = List.map E ts let (|E|) (e: Expr) = e.Tree - let (|ES|) (es: list) = es |> List.map (fun e -> e.Tree) + let (|ES|) (es: Expr list) = es |> List.map (fun e -> e.Tree) let (|FrontAndBack|_|) es = let rec loop acc xs = match xs with [] -> None | [h] -> Some (List.rev acc, h) | h :: t -> loop (h :: acc) t loop [] es @@ -515,10 +550,34 @@ module Patterns = | E(CombTerm(NewObjectOp ty, e)) -> Some(ty, e) | _ -> None [] - let (|Call|_|) input = + let (|Call|_|) input = match input with | E(CombTerm(StaticMethodCallOp minfo, args)) -> Some(None, minfo, args) - | E(CombTerm(InstanceMethodCallOp minfo, (obj :: args))) -> Some(Some obj, minfo, args) + | E(CombTerm(InstanceMethodCallOp minfo, (obj::args))) -> Some(Some(obj), minfo, args) + + | E(CombTerm(StaticMethodCallWOp (minfo, _minfoW, nWitnesses), args)) -> + Some(None, minfo, List.skip nWitnesses args) + + | E(CombTerm(InstanceMethodCallWOp (minfo, _minfoW, nWitnesses), args)) -> + let argsWithoutWitnesses = List.skip nWitnesses args + match argsWithoutWitnesses with + | obj :: argsWithoutObj -> Some (Some obj, minfo, argsWithoutObj) + | _ -> None + + | _ -> None + + [] + let (|CallWithWitnesses|_|) input = + match input with + | E(CombTerm(StaticMethodCallWOp (minfo, minfoW, nWitnesses), args)) -> Some(None, minfo, minfoW, List.take nWitnesses args, List.skip nWitnesses args) + | E(CombTerm(InstanceMethodCallWOp (minfo, minfoW, nWitnesses), args)) -> + if args.Length >= nWitnesses then + let witnessArgs, argsWithoutWitnesses = List.splitAt nWitnesses args + match argsWithoutWitnesses with + | objArgs :: argsWithoutObjectArg -> Some (Some objArgs, minfo, minfoW, witnessArgs, argsWithoutObjectArg) + | _ -> None + else + None | _ -> None let (|LetRaw|_|) input = @@ -629,6 +688,8 @@ module Patterns = | NewObjectOp ctor, _ -> ctor.DeclaringType | InstanceMethodCallOp minfo, _ -> minfo.ReturnType |> removeVoid | StaticMethodCallOp minfo, _ -> minfo.ReturnType |> removeVoid + | InstanceMethodCallWOp (_, minfoW, _), _ -> minfoW.ReturnType |> removeVoid + | StaticMethodCallWOp (_, minfoW, _), _ -> minfoW.ReturnType |> removeVoid | CoerceOp ty, _ -> ty | SequentialOp, [_;b] -> typeOf b | ForIntegerRangeLoopOp, _ -> typeof @@ -674,7 +735,7 @@ module Patterns = if (not (assignableFrom expectedType receivedType)) then invalidArg "receivedType" (String.Format(threeHoleSR, name, expectedType, receivedType)) - let checkArgs (paramInfos: ParameterInfo[]) (args:list) = + let checkArgs (paramInfos: ParameterInfo[]) (args:Expr list) = if (paramInfos.Length <> args.Length) then invalidArg "args" (SR.GetString(SR.QincorrectNumArgs)) List.iter2 ( fun (p:ParameterInfo) a -> checkTypesWeakSR p.ParameterType (typeOf a) "args" (SR.GetString(SR.QtmmInvalidParam))) @@ -765,7 +826,7 @@ module Patterns = mkFE1 (TupleGetOp (ty, n)) x // Records - let mkNewRecord (ty, args:list) = + let mkNewRecord (ty, args:Expr list) = let mems = FSharpType.GetRecordFields(ty, publicOrPrivateBindingFlags) if (args.Length <> mems.Length) then invalidArg "args" (SR.GetString(SR.QincompatibleRecordLength)) List.iter2 (fun (minfo:PropertyInfo) a -> checkTypesSR minfo.PropertyType (typeOf a) "recd" (SR.GetString(SR.QtmmIncorrectArgForRecord))) (Array.toList mems) args @@ -773,7 +834,7 @@ module Patterns = // Discriminated unions - let mkNewUnionCase (unionCase:UnionCaseInfo, args:list) = + let mkNewUnionCase (unionCase:UnionCaseInfo, args:Expr list) = if Unchecked.defaultof = unionCase then raise (new ArgumentNullException()) let sargs = unionCase.GetFields() if (args.Length <> sargs.Length) then invalidArg "args" (SR.GetString(SR.QunionNeedsDiffNumArgs)) @@ -816,7 +877,7 @@ module Patterns = | true -> mkFE1 (StaticFieldSetOp finfo) value | false -> invalidArg "finfo" (SR.GetString(SR.QnonStaticNoReceiverObject)) - let mkInstanceFieldSet (obj, finfo:FieldInfo, value:Expr) = + let mkInstanceFieldSet (obj, finfo: FieldInfo, value: Expr) = if Unchecked.defaultof = finfo then raise (new ArgumentNullException()) checkTypesSR (typeOf value) finfo.FieldType "value" (SR.GetString(SR.QtmmBadFieldType)) match finfo.IsStatic with @@ -825,15 +886,15 @@ module Patterns = mkFE2 (InstanceFieldSetOp finfo) (obj, value) | true -> invalidArg "finfo" (SR.GetString(SR.QstaticWithReceiverObject)) - let mkCtorCall (ci:ConstructorInfo, args:list) = + let mkCtorCall (ci: ConstructorInfo, args: Expr list) = if Unchecked.defaultof = ci then raise (new ArgumentNullException()) checkArgs (ci.GetParameters()) args mkFEN (NewObjectOp ci) args - let mkDefaultValue (ty:Type) = + let mkDefaultValue (ty: Type) = mkFE0 (DefaultValueOp ty) - let mkStaticPropGet (pinfo:PropertyInfo, args:list) = + let mkStaticPropGet (pinfo:PropertyInfo, args:Expr list) = if Unchecked.defaultof = pinfo then raise (new ArgumentNullException()) if (not pinfo.CanRead) then invalidArg "pinfo" (SR.GetString(SR.QreadingSetOnly)) checkArgs (pinfo.GetIndexParameters()) args @@ -841,7 +902,7 @@ module Patterns = | true -> mkFEN (StaticPropGetOp pinfo) args | false -> invalidArg "pinfo" (SR.GetString(SR.QnonStaticNoReceiverObject)) - let mkInstancePropGet (obj, pinfo:PropertyInfo, args:list) = + let mkInstancePropGet (obj, pinfo:PropertyInfo, args:Expr list) = if Unchecked.defaultof = pinfo then raise (new ArgumentNullException()) if (not pinfo.CanRead) then invalidArg "pinfo" (SR.GetString(SR.QreadingSetOnly)) checkArgs (pinfo.GetIndexParameters()) args @@ -851,7 +912,7 @@ module Patterns = mkFEN (InstancePropGetOp pinfo) (obj :: args) | true -> invalidArg "pinfo" (SR.GetString(SR.QstaticWithReceiverObject)) - let mkStaticPropSet (pinfo:PropertyInfo, args:list, value:Expr) = + let mkStaticPropSet (pinfo:PropertyInfo, args:Expr list, value:Expr) = if Unchecked.defaultof = pinfo then raise (new ArgumentNullException()) if (not pinfo.CanWrite) then invalidArg "pinfo" (SR.GetString(SR.QwritingGetOnly)) checkArgs (pinfo.GetIndexParameters()) args @@ -859,7 +920,7 @@ module Patterns = | true -> mkFEN (StaticPropSetOp pinfo) (args@[value]) | false -> invalidArg "pinfo" (SR.GetString(SR.QnonStaticNoReceiverObject)) - let mkInstancePropSet (obj, pinfo:PropertyInfo, args:list, value:Expr) = + let mkInstancePropSet (obj, pinfo:PropertyInfo, args:Expr list, value:Expr) = if Unchecked.defaultof = pinfo then raise (new ArgumentNullException()) if (not pinfo.CanWrite) then invalidArg "pinfo" (SR.GetString(SR.QwritingGetOnly)) checkArgs (pinfo.GetIndexParameters()) args @@ -869,7 +930,7 @@ module Patterns = mkFEN (InstancePropSetOp pinfo) (obj :: (args@[value])) | true -> invalidArg "pinfo" (SR.GetString(SR.QstaticWithReceiverObject)) - let mkInstanceMethodCall (obj, minfo:MethodInfo, args:list) = + let mkInstanceMethodCall (obj, minfo: MethodInfo, args: Expr list) = if Unchecked.defaultof = minfo then raise (new ArgumentNullException()) checkArgs (minfo.GetParameters()) args match minfo.IsStatic with @@ -878,13 +939,29 @@ module Patterns = mkFEN (InstanceMethodCallOp minfo) (obj :: args) | true -> invalidArg "minfo" (SR.GetString(SR.QstaticWithReceiverObject)) - let mkStaticMethodCall (minfo:MethodInfo, args:list) = + let mkInstanceMethodCallW (obj, minfo: MethodInfo, minfoW: MethodInfo, nWitnesses: int, args: Expr list) = + if Unchecked.defaultof = minfo then raise (new ArgumentNullException()) + checkArgs (minfoW.GetParameters()) args + match minfoW.IsStatic with + | false -> + checkObj minfo obj + mkFEN (InstanceMethodCallWOp (minfo, minfoW, nWitnesses)) (obj::args) + | true -> invalidArg "minfo" (SR.GetString(SR.QstaticWithReceiverObject)) + + let mkStaticMethodCall (minfo: MethodInfo, args: Expr list) = if Unchecked.defaultof = minfo then raise (new ArgumentNullException()) checkArgs (minfo.GetParameters()) args match minfo.IsStatic with | true -> mkFEN (StaticMethodCallOp minfo) args | false -> invalidArg "minfo" (SR.GetString(SR.QnonStaticNoReceiverObject)) + let mkStaticMethodCallW (minfo: MethodInfo, minfoW: MethodInfo, nWitnesses: int, args: Expr list) = + if Unchecked.defaultof = minfo then raise (new ArgumentNullException()) + checkArgs (minfoW.GetParameters()) args + match minfo.IsStatic with + | true -> mkFEN (StaticMethodCallWOp (minfo, minfoW, nWitnesses)) args + | false -> invalidArg "minfo" (SR.GetString(SR.QnonStaticNoReceiverObject)) + let mkForLoop (v:Var, lowerBound, upperBound, body) = checkTypesSR (typeof) (typeOf lowerBound) "lowerBound" (SR.GetString(SR.QtmmLowerUpperBoundMustBeInt)) checkTypesSR (typeof) (typeOf upperBound) "upperBound" (SR.GetString(SR.QtmmLowerUpperBoundMustBeInt)) @@ -904,7 +981,7 @@ module Patterns = mkFE1 (NewDelegateOp ty) e let mkLet (v, e, b) = - checkBind (v, e) + checkBind (v, e); mkLetRaw (e, mkLambda(v, b)) //let mkLambdas(vs, b) = mkRLinear mkLambdaRaw (vs, (b:>Expr)) @@ -914,7 +991,7 @@ module Patterns = | [x] -> mkApplication (f, x) | _ -> mkApplication (f, mkNewTuple args) - let mkApplications(f: Expr, es:list>) = mkLLinear mkTupledApplication (f, es) + let mkApplications(f: Expr, es:list) = mkLLinear mkTupledApplication (f, es) let mkIteratedLambdas(vs, b) = mkRLinear mkLambda (vs, b) @@ -980,7 +1057,7 @@ module Patterns = res // return MethodInfo for (generic) type's (generic) method match List.tryFind select methInfos with - | None -> raise <| System.InvalidOperationException (SR.GetString SR.QcannotBindToMethod) + | None -> raise <| System.InvalidOperationException (SR.GetString SR.QcannotBindToMethod) | Some methInfo -> methInfo let bindMethodHelper (parentT: Type, nm, marity, argtys, rty) = @@ -1012,11 +1089,6 @@ module Patterns = // tries to locate unique function in a given type // in case of multiple candidates returns None so bindModuleFunctionWithCallSiteArgs will be used for more precise resolution - let bindModuleFunction (ty:Type, nm) = - match ty.GetMethods staticBindingFlags |> Array.filter (fun mi -> mi.Name = nm) with - | [||] -> raise <| System.InvalidOperationException (String.Format(SR.GetString(SR.QcannotBindFunction), nm, ty.ToString())) - | [| res |] -> Some res - | _ -> None let bindModuleFunctionWithCallSiteArgs (ty:Type, nm, argTypes : Type list, tyArgs : Type list) = let argTypes = List.toArray argTypes @@ -1342,8 +1414,8 @@ module Patterns = | _ -> invalidArg "tys" (SR.GetString(SR.QexpectedOneType)) let mkNamedTycon (tcName, assembly:Assembly) = - match assembly.GetType tcName with - | null -> + match assembly.GetType(tcName) with + | null -> // For some reason we can get 'null' returned here even when a type with the right name exists... Hence search the slow way... match (assembly.GetTypes() |> Array.tryFind (fun a -> a.FullName = tcName)) with | Some ty -> ty @@ -1396,7 +1468,7 @@ module Patterns = let rec u_dtype st : (int -> Type) -> Type = let tag = u_byte_as_int st match tag with - | 0 -> u_int st |> (fun x env -> env x) + | 0 -> u_int st |> (fun x env -> env x) | 1 -> u_tup2 u_tyconstSpec (u_list u_dtype) st |> (fun (a, b) env -> a (appL b env)) | _ -> failwith "u_dtype" @@ -1434,44 +1506,34 @@ module Patterns = let rec u_Expr st = let tag = u_byte_as_int st match tag with - | 0 -> - let a = u_constSpec st - let b = u_dtypes st - let args = u_list u_Expr st - (fun (env:BindingEnv) -> - let args = List.map (fun e -> e env) args - let a = - match a with - | Unique v -> v - | Ambiguous f -> - let argTys = List.map typeOf args - f argTys - let tyargs = b env.typeInst - E (CombTerm (a tyargs, args))) - | 1 -> - let x = u_VarRef st - (fun env -> E(VarTerm (x env))) - | 2 -> - let a = u_VarDecl st - let b = u_Expr st - (fun env -> let v = a env in E(LambdaTerm(v, b (addVar env v)))) - | 3 -> - let a = u_dtype st - let idx = u_int st - (fun env -> E(HoleTerm(a env.typeInst, idx))) - | 4 -> - let a = u_Expr st - (fun env -> mkQuote(a env, true)) - | 5 -> - let a = u_Expr st - let attrs = u_list u_Expr st - (fun env -> let e = (a env) in EA(e.Tree, (e.CustomAttributes @ List.map (fun attrf -> attrf env) attrs))) - | 6 -> - let a = u_dtype st - (fun env -> mkVar(Var.Global("this", a env.typeInst))) - | 7 -> - let a = u_Expr st - (fun env -> mkQuote(a env, false)) + | 0 -> u_tup3 u_opSpec u_dtypes (u_list u_Expr) st + |> (fun (a, b, args) (env:BindingEnv) -> + let args = List.map (fun e -> e env) args + let a = + match a with + | Unique v -> v + | Ambiguous f -> + let argTys = List.map typeOf args + f argTys + let tyargs = b env.typeInst + E(CombTerm(a tyargs, args ))) + | 1 -> let x = u_VarRef st + (fun env -> E(VarTerm (x env))) + | 2 -> let a = u_VarDecl st + let b = u_Expr st + (fun env -> let v = a env in E(LambdaTerm(v, b (addVar env v)))) + | 3 -> let a = u_dtype st + let idx = u_int st + (fun env -> E(HoleTerm(a env.typeInst, idx))) + | 4 -> let a = u_Expr st + (fun env -> mkQuote(a env, true)) + | 5 -> let a = u_Expr st + let attrs = u_list u_Expr st + (fun env -> let e = (a env) in EA(e.Tree, (e.CustomAttributes @ List.map (fun attrf -> attrf env) attrs))) + | 6 -> let a = u_dtype st + (fun env -> mkVar(Var.Global("this", a env.typeInst))) + | 7 -> let a = u_Expr st + (fun env -> mkQuote(a env, false)) | _ -> failwith "u_Expr" and u_VarDecl st = @@ -1494,13 +1556,39 @@ module Patterns = let case, i = u_tup2 u_UnionCaseInfo u_int st (fun tyargs -> getUnionCaseInfoField(case tyargs, i)) - and u_ModuleDefn st = + and u_ModuleDefn witnessInfo st = let (ty, nm, isProp) = u_tup3 u_NamedType u_string u_bool st if isProp then Unique(StaticPropGetOp(bindModuleProperty(ty, nm))) else - match bindModuleFunction(ty, nm) with - | Some mi -> Unique(StaticMethodCallOp mi) - | None -> Ambiguous(fun argTypes tyargs -> StaticMethodCallOp(bindModuleFunctionWithCallSiteArgs(ty, nm, argTypes, tyargs))) + let meths = ty.GetMethods staticBindingFlags |> Array.filter (fun mi -> mi.Name = nm) + match meths with + | [||] -> + raise <| System.InvalidOperationException (String.Format(SR.GetString(SR.QcannotBindFunction), nm, ty.ToString())) + | [| minfo |] -> + match witnessInfo with + | None -> + Unique(StaticMethodCallOp(minfo)) + | Some (nmW, nWitnesses) -> + let methsW = ty.GetMethods(staticBindingFlags) |> Array.filter (fun mi -> mi.Name = nmW) + match methsW with + | [||] -> + raise <| System.InvalidOperationException (String.Format(SR.GetString(SR.QcannotBindFunction), nmW, ty.ToString())) + | [| minfoW |] -> + Unique(StaticMethodCallWOp(minfo, minfoW, nWitnesses)) + | _ -> + Ambiguous(fun argTypes tyargs -> + let minfoW = bindModuleFunctionWithCallSiteArgs(ty, nm, argTypes, tyargs) + StaticMethodCallWOp(minfo, minfoW, nWitnesses)) + | _ -> + Ambiguous(fun argTypes tyargs -> + match witnessInfo with + | None -> + let minfo = bindModuleFunctionWithCallSiteArgs(ty, nm, argTypes, tyargs) + StaticMethodCallOp minfo + | Some (nmW, nWitnesses) -> + let minfo = bindModuleFunctionWithCallSiteArgs(ty, nm, List.skip nWitnesses argTypes, tyargs) + let minfoW = bindModuleFunctionWithCallSiteArgs(ty, nmW, argTypes, tyargs) + StaticMethodCallWOp(minfo, minfoW, nWitnesses)) and u_MethodInfoData st = u_tup5 u_NamedType (u_list u_dtype) u_dtype u_string u_int st @@ -1515,10 +1603,10 @@ module Patterns = let tag = u_byte_as_int st match tag with | 0 -> - match u_ModuleDefn st with - | Unique(StaticMethodCallOp minfo) -> (minfo :> MethodBase) - | Unique(StaticPropGetOp pinfo) -> (pinfo.GetGetMethod true :> MethodBase) - | Ambiguous(_) -> raise (System.Reflection.AmbiguousMatchException()) + match u_ModuleDefn None st with + | Unique (StaticMethodCallOp minfo) -> (minfo :> MethodBase) + | Unique (StaticPropGetOp pinfo) -> (pinfo.GetGetMethod(true) :> MethodBase) + | Ambiguous _ -> raise (System.Reflection.AmbiguousMatchException()) | _ -> failwith "unreachable" | 1 -> let ((tc, _, _, methName, _) as data) = u_MethodInfoData st @@ -1532,26 +1620,44 @@ module Patterns = let data = u_CtorInfoData st let cinfo = bindGenericCtor data (cinfo :> MethodBase) + | 3 -> + let methNameW = u_string st + let nWitnesses = u_int st + match u_ModuleDefn (Some (methNameW, nWitnesses)) st with + | Unique(StaticMethodCallOp(minfo)) -> (minfo :> MethodBase) + | Unique(StaticMethodCallWOp(_minfo, minfoW, _)) -> (minfoW :> MethodBase) + | Unique(StaticPropGetOp(pinfo)) -> (pinfo.GetGetMethod(true) :> MethodBase) + | Ambiguous(_) -> raise (System.Reflection.AmbiguousMatchException()) + | _ -> failwith "unreachable" | _ -> failwith "u_MethodBase" - and u_constSpec st = + and instModuleDefnOp r tyargs = + match r with + | StaticMethodCallOp(minfo) -> StaticMethodCallOp(instMeth(minfo, tyargs)) + | StaticMethodCallWOp(minfo, minfoW, n) -> StaticMethodCallWOp(instMeth(minfo, tyargs), instMeth(minfoW, tyargs), n) + // OK to throw away the tyargs here since this only non-generic values in modules get represented by static properties + | x -> x + + and u_opSpec st = let tag = u_byte_as_int st if tag = 1 then - let bindModuleDefn r tyargs = - match r with - | StaticMethodCallOp minfo -> StaticMethodCallOp(instMeth(minfo, tyargs)) - // OK to throw away the tyargs here since this only non-generic values in modules get represented by static properties - | x -> x - match u_ModuleDefn st with - | Unique r -> Unique(bindModuleDefn r) - | Ambiguous f -> Ambiguous(fun argTypes tyargs -> bindModuleDefn (f argTypes tyargs) tyargs) + match u_ModuleDefn None st with + | Unique r -> Unique (instModuleDefnOp r) + | Ambiguous f -> Ambiguous (fun argTypes tyargs -> instModuleDefnOp (f argTypes tyargs) tyargs) + elif tag = 51 then + let nmW = u_string st + let nWitnesses = u_int st + match u_ModuleDefn (Some (nmW, nWitnesses)) st with + | Unique r -> Unique(instModuleDefnOp r) + | Ambiguous f -> Ambiguous(fun argTypes tyargs -> instModuleDefnOp (f argTypes tyargs) tyargs) else let constSpec = match tag with | 0 -> u_void st |> (fun () NoTyArgs -> IfThenElseOp) + // 1 taken above | 2 -> u_void st |> (fun () NoTyArgs -> LetRecOp) - | 3 -> u_NamedType st |> (fun x tyargs -> NewRecordOp (mkNamedType (x, tyargs))) + | 3 -> u_NamedType st |> (fun x tyargs -> NewRecordOp (mkNamedType(x, tyargs))) | 4 -> u_RecdField st |> (fun prop tyargs -> InstancePropGetOp(prop tyargs)) | 5 -> u_UnionCaseInfo st |> (fun unionCase tyargs -> NewUnionCaseOp(unionCase tyargs)) | 6 -> u_UnionCaseField st |> (fun prop tyargs -> InstancePropGetOp(prop tyargs) ) @@ -1573,9 +1679,9 @@ module Patterns = | 22 -> u_int64 st |> (fun a (OneTyArg tyarg) -> mkLiftedValueOpG (a, tyarg)) | 23 -> u_uint64 st |> (fun a (OneTyArg tyarg) -> mkLiftedValueOpG (a, tyarg)) | 24 -> u_void st |> (fun () NoTyArgs -> mkLiftedValueOpG ((), typeof)) - | 25 -> u_PropInfoData st |> (fun (a, b, c, d) tyargs -> let pinfo = bindProp(a, b, c, d, tyargs) in if pinfoIsStatic pinfo then StaticPropGetOp pinfo else InstancePropGetOp pinfo) - | 26 -> u_CtorInfoData st |> (fun (a, b) tyargs -> NewObjectOp (bindCtor(a, b, tyargs))) - | 28 -> u_void st |> (fun () (OneTyArg ty) -> CoerceOp ty) + | 25 -> u_PropInfoData st |> (fun (a, b, c, d) tyargs -> let pinfo = bindProp (a, b, c, d, tyargs) in if pinfoIsStatic pinfo then StaticPropGetOp(pinfo) else InstancePropGetOp(pinfo)) + | 26 -> u_CtorInfoData st |> (fun (a, b) tyargs -> NewObjectOp (bindCtor (a, b, tyargs))) + | 28 -> u_void st |> (fun () (OneTyArg(ty)) -> CoerceOp ty) | 29 -> u_void st |> (fun () NoTyArgs -> SequentialOp) | 30 -> u_void st |> (fun () NoTyArgs -> ForIntegerRangeLoopOp) | 31 -> u_MethodInfoData st |> (fun p tyargs -> let minfo = bindMeth(p, tyargs) in if minfo.IsStatic then StaticMethodCallOp minfo else InstanceMethodCallOp minfo) @@ -1597,7 +1703,14 @@ module Patterns = | 47 -> u_void st |> (fun () NoTyArgs -> TryFinallyOp) | 48 -> u_void st |> (fun () NoTyArgs -> TryWithOp) | 49 -> u_void st |> (fun () NoTyArgs -> VarSetOp) - | _ -> failwithf "u_constSpec, unrecognized tag %d" tag + | 50 -> + u_tup3 u_MethodInfoData u_MethodInfoData u_int st |> (fun (m1, m2, n) tyargs -> + let minfo = bindMeth (m1, tyargs) + let minfoW = bindMeth (m2, tyargs) + if minfo.IsStatic then StaticMethodCallWOp(minfo, minfoW, n) + else InstanceMethodCallWOp(minfo, minfoW, n)) + // 51 taken above + | _ -> failwithf "u_opSpec, unrecognized tag %d" tag Unique constSpec let u_ReflectedDefinition = u_tup2 u_MethodBase u_Expr @@ -1953,6 +2066,16 @@ type Expr with checkNonNull "methodInfo" methodInfo mkInstanceMethodCall (obj, methodInfo, arguments) + static member CallWithWitnesses (methodInfo:MethodInfo, methodInfoWithWitnesses:MethodInfo, witnessArguments, arguments) = + checkNonNull "methodInfo" methodInfo + checkNonNull "methodInfoWithWitnesses" methodInfoWithWitnesses + mkStaticMethodCallW (methodInfo, methodInfoWithWitnesses, List.length witnessArguments, witnessArguments@arguments) + + static member CallWithWitnesses (obj:Expr, methodInfo:MethodInfo, methodInfoWithWitnesses:MethodInfo, witnessArguments, arguments) = + checkNonNull "methodInfo" methodInfo + checkNonNull "methodInfoWithWitnesses" methodInfoWithWitnesses + mkInstanceMethodCallW (obj, methodInfo, methodInfoWithWitnesses, List.length witnessArguments, witnessArguments@arguments) + static member Coerce (source:Expr, target:Type) = checkNonNull "target" target mkCoerce (target, source) @@ -2272,9 +2395,11 @@ module ExprShape = | InstanceFieldSetOp finfo, [obj;v] -> mkInstanceFieldSet(obj, finfo, v) | StaticFieldSetOp finfo, [v] -> mkStaticFieldSet(finfo, v) | NewObjectOp minfo, _ -> mkCtorCall(minfo, arguments) - | DefaultValueOp ty, _ -> mkDefaultValue ty + | DefaultValueOp ty, _ -> mkDefaultValue(ty) | StaticMethodCallOp minfo, _ -> mkStaticMethodCall(minfo, arguments) - | InstanceMethodCallOp minfo, obj :: args -> mkInstanceMethodCall(obj, minfo, args) + | InstanceMethodCallOp minfo, obj::args -> mkInstanceMethodCall(obj, minfo, args) + | StaticMethodCallWOp (minfo, minfoW, n), _ -> mkStaticMethodCallW(minfo, minfoW, n, arguments) + | InstanceMethodCallWOp (minfo, minfoW, n), obj::args -> mkInstanceMethodCallW(obj, minfo, minfoW, n, args) | CoerceOp ty, [arg] -> mkCoerce(ty, arg) | NewArrayOp ty, _ -> mkNewArray(ty, arguments) | NewDelegateOp ty, [arg] -> mkNewDelegate(ty, arg) diff --git a/src/fsharp/FSharp.Core/quotations.fsi b/src/fsharp/FSharp.Core/quotations.fsi index f9ab5d7089f..80517d5d879 100644 --- a/src/fsharp/FSharp.Core/quotations.fsi +++ b/src/fsharp/FSharp.Core/quotations.fsi @@ -84,20 +84,37 @@ type Expr = /// The function to apply. /// The list of lists of arguments to the function. /// The resulting expression. - static member Applications: functionExpr:Expr * arguments:list> -> Expr + static member Applications: functionExpr:Expr * arguments:list -> Expr /// Builds an expression that represents a call to an static method or module-bound function /// The MethodInfo describing the method to call. /// The list of arguments to the method. /// The resulting expression. - static member Call : methodInfo:MethodInfo * arguments:list -> Expr + static member Call : methodInfo:MethodInfo * arguments:Expr list -> Expr /// Builds an expression that represents a call to an instance method associated with an object /// The input object. /// The description of the method to call. /// The list of arguments to the method. /// The resulting expression. - static member Call : obj:Expr * methodInfo:MethodInfo * arguments:list -> Expr + static member Call : obj:Expr * methodInfo: MethodInfo * arguments:Expr list -> Expr + + /// Builds an expression that represents a call to an static method or module-bound function + /// The MethodInfo describing the method to call. + /// The additional MethodInfo describing the method to call, accepting witnesses. + /// The list of witnesses to the method. + /// The list of arguments to the method. + /// The resulting expression. + static member CallWithWitnesses: methodInfo: MethodInfo * methodInfoWithWitnesses: MethodInfo * witnesses: Expr list * arguments: Expr list -> Expr + + /// Builds an expression that represents a call to an instance method associated with an object + /// The input object. + /// The description of the method to call. + /// The additional MethodInfo describing the method to call, accepting witnesses. + /// The list of witnesses to the method. + /// The list of arguments to the method. + /// The resulting expression. + static member CallWithWitnesses: obj:Expr * methodInfo:MethodInfo * methodInfoWithWitnesses: MethodInfo * witnesses: Expr list * arguments:Expr list -> Expr /// Builds an expression that represents the coercion of an expression to a type /// The expression to coerce. @@ -370,7 +387,7 @@ type Expr = /// The spliced expressions to replace references to spliced expressions. /// The serialized form of the quoted expression. /// The resulting expression. - static member Deserialize : qualifyingType:System.Type * spliceTypes:list * spliceExprs:list * bytes:byte[] -> Expr + static member Deserialize : qualifyingType:System.Type * spliceTypes:list * spliceExprs:Expr list * bytes:byte[] -> Expr /// This function is called automatically when quotation syntax (<@ @>) and other sources of /// quotations are used. @@ -449,6 +466,12 @@ module Patterns = [] val (|Call|_|) : input:Expr -> (Expr option * MethodInfo * Expr list) option + /// An active pattern to recognize expressions that represent calls to static and instance methods, and functions defined in modules, including witness arguments + /// The input expression to match against. + /// (Expr option * MethodInfo * MethodInfo * Expr list) option + [] + val (|CallWithWitnesses|_|) : input:Expr -> (Expr option * MethodInfo * MethodInfo * Expr list * Expr list) option + /// An active pattern to recognize expressions that represent coercions from one type to another /// The input expression to match against. /// (Expr * Type) option @@ -770,7 +793,7 @@ module DerivedPatterns = /// instance method), the generic type instantiation (non-empty if the target is a generic /// instantiation), and the arguments to the function or method. [] - val (|SpecificCall|_|) : templateParameter:Expr -> (Expr -> (Expr option * list * list) option) + val (|SpecificCall|_|) : templateParameter:Expr -> (Expr -> (Expr option * list * Expr list) option) /// An active pattern to recognize methods that have an associated ReflectedDefinition /// The description of the method. @@ -801,11 +824,11 @@ module ExprShape = val (|ShapeVar|ShapeLambda|ShapeCombination|) : input:Expr -> Choice)> // ConstApp + (obj * Expr list)> // ConstApp /// Re-build combination expressions. The first parameter should be an object /// returned by the ShapeCombination case of the active pattern in this module. /// The input shape. /// The list of arguments. /// The rebuilt expression. - val RebuildShapeCombination : shape:obj * arguments:list -> Expr + val RebuildShapeCombination : shape:obj * arguments:Expr list -> Expr diff --git a/src/fsharp/IlxGen.fs b/src/fsharp/IlxGen.fs index 3c8ac06ee1f..6e0f4dec0b3 100644 --- a/src/fsharp/IlxGen.fs +++ b/src/fsharp/IlxGen.fs @@ -9,6 +9,7 @@ module internal FSharp.Compiler.IlxGen open System.IO open System.Reflection open System.Collections.Generic +open System.Collections.Immutable open Internal.Utilities open Internal.Utilities.Collections @@ -229,9 +230,9 @@ type cenv = /// The ImportMap for reading IL amap: ImportMap - /// A callback for TcVal in the typechecker. Used to generalize values when finding witnesses. + /// A callback for tcVal in the typechecker. Used to generalize values when finding witnesses. /// It is unfortunate this is needed but it is until we supply witnesses through the compiation. - TcVal: ConstraintSolver.TcValF + tcVal: ConstraintSolver.TcValF /// The TAST for the assembly being emitted viewCcu: CcuThunk @@ -250,6 +251,7 @@ type cenv = /// Used to apply forced inlining optimizations to witnesses generated late during codegen mutable optimizeDuringCodeGen: (Expr -> Expr) + } @@ -683,10 +685,10 @@ type IlxClosureInfo = cloArityInfo: ArityInfo /// The formal return type - cloILFormalRetTy: ILType + ilCloFormalReturnTy: ILType /// An immutable array of free variable descriptions for the closure - cloILFreeVars: IlxClosureFreeVar[] + ilCloAllFreeVars: IlxClosureFreeVar[] /// The ILX specification for the closure cloSpec: IlxClosureSpec @@ -697,9 +699,13 @@ type IlxClosureInfo = /// The generic parameters for the closure, i.e. the type variables it captures cloILGenericParams: IL.ILGenericParameterDefs - /// The free variables for the closure, i.e. the values it captures + /// The captured variables for the closure cloFreeVars: Val list + cloFreeTyvars: Typars + + cloWitnessInfos: TraitWitnessInfos + /// ILX view of the lambdas for the closures ilCloLambdas: IlxClosureLambdas @@ -738,15 +744,15 @@ type ValStorage = /// Indicates the value is stored in a static field. | StaticField of ILFieldSpec * ValRef * (*hasLiteralAttr:*)bool * ILType * string * ILType * ILMethodRef * ILMethodRef * OptionalShadowLocal - /// Indicates the value is "stored" as a property that recomputes it each time it is referenced. Used for simple constants that do not cause initialization triggers - | StaticProperty of ILMethodSpec * OptionalShadowLocal + /// Indicates the value is represented as a property that recomputes it each time it is referenced. Used for simple constants that do not cause initialization triggers + | StaticProperty of ILMethodSpec * OptionalShadowLocal - /// Indicates the value is "stored" as a IL static method (in a "main" class for a F# + /// Indicates the value is represented as an IL method (in a "main" class for a F# /// compilation unit, or as a member) according to its inferred or specified arity. - | Method of ValReprInfo * ValRef * ILMethodSpec * Range.range * ArgReprInfo list * TType list * ArgReprInfo + | Method of ValReprInfo * ValRef * ILMethodSpec * ILMethodSpec * Range.range * Typars * Typars * CurriedArgInfos * ArgReprInfo list * TraitWitnessInfos * TType list * ArgReprInfo /// Indicates the value is stored at the given position in the closure environment accessed via "ldarg 0" - | Env of ILType * int * ILFieldSpec * NamedLocalIlxClosureInfo ref option + | Env of ILType * ILFieldSpec * NamedLocalIlxClosureInfo ref option /// Indicates that the value is an argument of a method being generated | Arg of int @@ -783,11 +789,13 @@ and BranchCallItem = ArityInfo * // Arg infos for compiled form of F# method or value (TType * ArgReprInfo) list list * - // Typars for F# method or value - Tast.Typars * - // Typars for F# method or value + // Typars the F# method or value + Typars * + // num obj args in IL int * - // num obj args + // num witness args in IL + int * + // num actual args in IL int /// Represents a place we can branch to @@ -815,7 +823,10 @@ and IlxGenEnv = /// All values in scope valsInScope: ValMap> - /// For optimizing direct tail recursion to a loop - mark says where to branch to. Length is 0 or 1. + /// All witnesses in scope + witnessesInScope: ImmutableDictionary + + /// For optimizing direct tail recursion to a loop - mark says where to branch to. Length is 0 or 1. /// REVIEW: generalize to arbitrary nested local loops?? innerVals: (ValRef * (BranchCallItem * Mark)) list @@ -878,7 +889,14 @@ let AddStorageForVal (g: TcGlobals) (v, s) eenv = else eenv -let AddStorageForLocalVals g vals eenv = List.foldBack (fun (v, s) acc -> AddStorageForVal g (v, notlazy s) acc) vals eenv +let AddStorageForLocalVals g vals eenv = + List.foldBack (fun (v, s) acc -> AddStorageForVal g (v, notlazy s) acc) vals eenv + +let AddStorageForLocalWitness eenv (w,s) = + { eenv with witnessesInScope = eenv.witnessesInScope.SetItem (w, s) } + +let AddStorageForLocalWitnesses witnesses eenv = + (eenv, witnesses) ||> List.fold AddStorageForLocalWitness //-------------------------------------------------------------------------- // Lookup eenv @@ -895,6 +913,11 @@ let StorageForVal m v eenv = let StorageForValRef m (v: ValRef) eenv = StorageForVal m v.Deref eenv +let TryStorageForWitness eenv (w: TraitWitnessInfo) = + match eenv.witnessesInScope.TryGetValue w with + | true, storage -> Some storage + | _ -> None // failwithf "no storage for witness %s found in scope" w.MemberName + let IsValRefIsDllImport g (vref: ValRef) = vref.Attribs |> HasFSharpAttributeOpt g g.attrib_DllImportAttribute @@ -902,9 +925,9 @@ let IsValRefIsDllImport g (vref: ValRef) = /// as a method. let GetMethodSpecForMemberVal amap g (memberInfo: ValMemberInfo) (vref: ValRef) = let m = vref.Range - let tps, curriedArgInfos, returnTy, retInfo = + let tps, cxs, curriedArgInfos, returnTy, retInfo = assert(vref.ValReprInfo.IsSome) - GetTopValTypeInCompiledForm g (Option.get vref.ValReprInfo) vref.Type m + GetTopValTypeInCompiledForm g vref.ValReprInfo.Value vref.Type m let tyenvUnderTypars = TypeReprEnv.ForTypars tps let flatArgInfos = List.concat curriedArgInfos let isCtor = (memberInfo.MemberFlags.MemberKind = MemberKind.Constructor) @@ -949,15 +972,27 @@ let GetMethodSpecForMemberVal amap g (memberInfo: ValMemberInfo) (vref: ValRef) let ilMethodArgTys = GenParamTypes amap m tyenvUnderTypars isSlotSig methodArgTys let ilMethodInst = GenTypeArgs amap m tyenvUnderTypars (List.map mkTyparTy mtps) let mspec = mkILInstanceMethSpecInTy (ilTy, vref.CompiledName, ilMethodArgTys, ilActualRetTy, ilMethodInst) + let mspecW = + if not g.generateWitnesses || cxs.IsEmpty then + mspec + else + let ilWitnessArgTys = GenTypes amap m tyenvUnderTypars (GenWitnessTys g cxs) + mkILInstanceMethSpecInTy (ilTy, ExtraWitnessMethodName vref.CompiledName, ilWitnessArgTys @ ilMethodArgTys, ilActualRetTy, ilMethodInst) - mspec, ctps, mtps, paramInfos, retInfo, methodArgTys + mspec, mspecW, ctps, mtps, curriedArgInfos, paramInfos, retInfo, cxs, methodArgTys else let methodArgTys, paramInfos = List.unzip flatArgInfos let ilMethodArgTys = GenParamTypes amap m tyenvUnderTypars false methodArgTys let ilMethodInst = GenTypeArgs amap m tyenvUnderTypars (List.map mkTyparTy mtps) let mspec = mkILStaticMethSpecInTy (ilTy, vref.CompiledName, ilMethodArgTys, ilActualRetTy, ilMethodInst) + let mspecW = + if not g.generateWitnesses || cxs.IsEmpty then + mspec + else + let ilWitnessArgTys = GenTypes amap m tyenvUnderTypars (GenWitnessTys g cxs) + mkILStaticMethSpecInTy (ilTy, ExtraWitnessMethodName vref.CompiledName, ilWitnessArgTys @ ilMethodArgTys, ilActualRetTy, ilMethodInst) - mspec, ctps, mtps, paramInfos, retInfo, methodArgTys + mspec, mspecW, ctps, mtps, curriedArgInfos, paramInfos, retInfo, cxs, methodArgTys /// Determine how a top-level value is represented, when representing as a field, by computing an ILFieldSpec let ComputeFieldSpecForVal(optIntraAssemblyInfo: IlxGenIntraAssemblyInfo option, isInteractive, g, ilTyForProperty, vspec: Val, nm, m, cloc, ilTy, ilGetterMethRef) = @@ -994,23 +1029,29 @@ let ComputeStorageForFSharpValue amap g cloc optIntraAssemblyInfo optShadowLocal /// Compute the representation information for an F#-declared member let ComputeStorageForFSharpMember amap g topValInfo memberInfo (vref: ValRef) m = - let mspec, _, _, paramInfos, retInfo, methodArgTys = GetMethodSpecForMemberVal amap g memberInfo vref - Method (topValInfo, vref, mspec, m, paramInfos, methodArgTys, retInfo) + let mspec, mspecW, ctps, mtps, curriedArgInfos, paramInfos, retInfo, witnessInfos, methodArgTys = GetMethodSpecForMemberVal amap g memberInfo vref + Method (topValInfo, vref, mspec, mspecW, m, ctps, mtps, curriedArgInfos, paramInfos, witnessInfos, methodArgTys, retInfo) /// Compute the representation information for an F#-declared function in a module or an F#-decalared extension member. /// Note, there is considerable overlap with ComputeStorageForFSharpMember/GetMethodSpecForMemberVal and these could be /// rationalized. let ComputeStorageForFSharpFunctionOrFSharpExtensionMember amap g cloc topValInfo (vref: ValRef) m = let nm = vref.CompiledName - let (tps, curriedArgInfos, returnTy, retInfo) = GetTopValTypeInCompiledForm g topValInfo vref.Type m + let (tps, cxs, curriedArgInfos, returnTy, retInfo) = GetTopValTypeInCompiledForm g topValInfo vref.Type m let tyenvUnderTypars = TypeReprEnv.ForTypars tps - let (methodArgTys, paramInfos) = curriedArgInfos |> List.concat |> List.unzip - let ilMethodArgTys = GenParamTypes amap m tyenvUnderTypars false methodArgTys + let (argTys, paramInfos) = curriedArgInfos |> List.concat |> List.unzip + let ilMethodArgTys = GenParamTypes amap m tyenvUnderTypars false argTys let ilRetTy = GenReturnType amap m tyenvUnderTypars returnTy let ilLocTy = mkILTyForCompLoc cloc let ilMethodInst = GenTypeArgs amap m tyenvUnderTypars (List.map mkTyparTy tps) let mspec = mkILStaticMethSpecInTy (ilLocTy, nm, ilMethodArgTys, ilRetTy, ilMethodInst) - Method (topValInfo, vref, mspec, m, paramInfos, methodArgTys, retInfo) + let mspecW = + if not g.generateWitnesses || cxs.IsEmpty then + mspec + else + let ilWitnessArgTys = GenTypes amap m tyenvUnderTypars (GenWitnessTys g cxs) + mkILStaticMethSpecInTy (ilLocTy, ExtraWitnessMethodName nm, (ilWitnessArgTys @ ilMethodArgTys), ilRetTy, ilMethodInst) + Method (topValInfo, vref, mspec, mspecW, m, [], tps, curriedArgInfos, paramInfos, cxs, argTys, retInfo) /// Determine if an F#-declared value, method or function is compiled as a method. let IsFSharpValCompiledAsMethod g (v: Val) = @@ -1529,7 +1570,7 @@ type AssemblyBuilder(cenv: cenv, anonTypeTable: AnonTypeGenerationTable) as mgbu member mgbuf.GetCurrentFields(tref: ILTypeRef) = gtdefs.FindNestedTypeDefBuilder(tref).GetCurrentFields() - member mgbuf.AddReflectedDefinition(vspec: Tast.Val, expr) = + member mgbuf.AddReflectedDefinition(vspec: Val, expr) = // preserve order by storing index of item let n = reflectedDefinitions.Count reflectedDefinitions.Add(vspec, (vspec.CompiledName, n, expr)) @@ -1751,7 +1792,9 @@ type CodeGenBuffer(m: range, res member cgbuf.mgbuf = mgbuf + member cgbuf.MethodName = methodName + member cgbuf.PreallocatedArgCount = alreadyUsedArgs member cgbuf.AllocLocal(ranges, ty, isFixed) = @@ -1873,10 +1916,10 @@ let discardAndReturnVoid = DiscardThen ReturnVoid // the bodies of methods in a couple of places //------------------------------------------------------------------------- -let CodeGenThen cenv mgbuf (entryPointInfo, methodName, eenv, alreadyUsedArgs, codeGenFunction, m) = +let CodeGenThen cenv mgbuf (tailCallInfo, methodName, eenv, alreadyUsedArgs, codeGenFunction, m) = let cgbuf = new CodeGenBuffer(m, mgbuf, methodName, alreadyUsedArgs) let start = CG.GenerateMark cgbuf "mstart" - let innerVals = entryPointInfo |> List.map (fun (v, kind) -> (v, (kind, start))) + let innerVals = tailCallInfo |> List.map (fun (v, kind) -> (v, (kind, start))) (* Call the given code generator *) codeGenFunction cgbuf {eenv with withinSEH=false @@ -1917,10 +1960,10 @@ let CodeGenThen cenv mgbuf (entryPointInfo, methodName, eenv, alreadyUsedArgs, c localDebugSpecs, hasSequencePoints) -let CodeGenMethod cenv mgbuf (entryPointInfo, methodName, eenv, alreadyUsedArgs, codeGenFunction, m) = +let CodeGenMethod cenv mgbuf (tailCallInfo, methodName, eenv, alreadyUsedArgs, codeGenFunction, m) = let locals, maxStack, lab2pc, instrs, exns, localDebugSpecs, hasSequencePoints = - CodeGenThen cenv mgbuf (entryPointInfo, methodName, eenv, alreadyUsedArgs, codeGenFunction, m) + CodeGenThen cenv mgbuf (tailCallInfo, methodName, eenv, alreadyUsedArgs, codeGenFunction, m) let code = IL.buildILCode methodName lab2pc instrs exns localDebugSpecs @@ -2188,8 +2231,10 @@ let rec GenExpr (cenv: cenv) (cgbuf: CodeGenBuffer) eenv sp expr sequel = ) -> // application of local type functions with type parameters = measure types and body = local value - inine the body GenExpr cenv cgbuf eenv sp v sequel - | Expr.App (f,fty, tyargs, args, m) -> - GenApp cenv cgbuf eenv (f, fty, tyargs, args, m) sequel + + | Expr.App (f, fty, tyargs, curriedArgs, m) -> + GenApp cenv cgbuf eenv (f, fty, tyargs, curriedArgs, m) sequel + | Expr.Val (v, _, m) -> GenGetVal cenv cgbuf eenv (v, m) sequel @@ -2304,9 +2349,9 @@ let rec GenExpr (cenv: cenv) (cgbuf: CodeGenBuffer) eenv sp expr sequel = and GenExprs cenv cgbuf eenv es = List.iter (fun e -> GenExpr cenv cgbuf eenv SPSuppress e Continue) es -and CodeGenMethodForExpr cenv mgbuf (spReq, entryPointInfo, methodName, eenv, alreadyUsedArgs, expr0, sequel0) = +and CodeGenMethodForExpr cenv mgbuf (spReq, tailCallInfo, methodName, eenv, alreadyUsedArgs, expr0, sequel0) = let _, code = - CodeGenMethod cenv mgbuf (entryPointInfo, methodName, eenv, alreadyUsedArgs, + CodeGenMethod cenv mgbuf (tailCallInfo, methodName, eenv, alreadyUsedArgs, (fun cgbuf eenv -> GenExpr cenv cgbuf eenv spReq expr0 sequel0), expr0.Range) code @@ -2859,8 +2904,7 @@ and GenUntupledArgExpr cenv cgbuf eenv m argInfos expr sequel = GenBinding cenv cgbuf eenvinner bind let tys = destRefTupleTy g ty assert (tys.Length = numRequiredExprs) - // TODO - tupInfoRef - argInfos |> List.iteri (fun i _ -> GenGetTupleField cenv cgbuf eenvinner (tupInfoRef (* TODO *), loce, tys, i, m) Continue) + argInfos |> List.iteri (fun i _ -> GenGetTupleField cenv cgbuf eenvinner (tupInfoRef, loce, tys, i, m) Continue) GenSequel cenv eenv.cloc cgbuf sequel ) @@ -2869,51 +2913,110 @@ and GenUntupledArgExpr cenv cgbuf eenv m argInfos expr sequel = // Generate calls (try to detect direct calls) //-------------------------------------------------------------------------- -and GenApp cenv cgbuf eenv (f, fty, tyargs, args, m) sequel = +and GenWitnessArgFromInfo cenv cgbuf eenv m witnessInfo = + let g = cenv.g + let storage = TryStorageForWitness eenv witnessInfo + match storage with + | None -> + System.Diagnostics.Debug.Assert(false, "expected storage for witness") + | Some storage -> + let ty = GenWitnessTy g witnessInfo + GenGetStorageAndSequel cenv cgbuf eenv m (ty, GenType cenv.amap m eenv.tyenv ty) storage None + +and GenWitnessArgsFromInfos cenv cgbuf eenv m witnessInfos = + let g = cenv.g + let inWitnessPassingScope = not eenv.witnessesInScope.IsEmpty + // Witness arguments are only generated in emitted 'inline' code where witness parameters are available. + if g.generateWitnesses && inWitnessPassingScope then + for witnessInfo in witnessInfos do + GenWitnessArgFromInfo cenv cgbuf eenv m witnessInfo + +and GenWitnessArgs cenv cgbuf eenv m tps tyargs = + let g = cenv.g + let inWitnessPassingScope = not eenv.witnessesInScope.IsEmpty + // Witness arguments are only generated in emitted 'inline' code where witness parameters are available. + if g.generateWitnesses && inWitnessPassingScope then + let mwitnesses = + ConstraintSolver.CodegenWitnessesForTyparInst cenv.tcVal g cenv.amap m tps tyargs + |> CommitOperationResult + + for witnessArg in mwitnesses do + match witnessArg with + | Choice1Of2 witnessInfo -> + GenWitnessArgFromInfo cenv cgbuf eenv m witnessInfo + | Choice2Of2 arg -> + GenExpr cenv cgbuf eenv SPSuppress arg Continue + +and GenApp (cenv: cenv) cgbuf eenv (f, fty, tyargs, curriedArgs, m) sequel = let g = cenv.g - match (f, tyargs, args) with - (* Look for tailcall to turn into branch *) + match (f, tyargs, curriedArgs) with + // Look for tailcall to turn into branch | (Expr.Val (v, _, _), _, _) when - match ListAssoc.tryFind g.valRefEq v eenv.innerVals with + match ListAssoc.tryFind cenv.g.valRefEq v eenv.innerVals with | Some (kind, _) -> (not v.IsConstructor && - (* when branch-calling methods we must have the right type parameters *) + // when branch-calling methods we must have the right type parameters (match kind with | BranchCallClosure _ -> true - | BranchCallMethod (_, _, tps, _, _) -> - (List.lengthsEqAndForall2 (fun ty tp -> typeEquiv g ty (mkTyparTy tp)) tyargs tps)) && - (* must be exact #args, ignoring tupling - we untuple if needed below *) + | BranchCallMethod (_, _, tps, _, _, _) -> + (List.lengthsEqAndForall2 (fun ty tp -> typeEquiv cenv.g ty (mkTyparTy tp)) tyargs tps)) && + // must be exact #args, ignoring tupling - we untuple if needed below (let arityInfo = match kind with | BranchCallClosure arityInfo - | BranchCallMethod (arityInfo, _, _, _, _) -> arityInfo - arityInfo.Length = args.Length + | BranchCallMethod (arityInfo, _, _, _, _, _) -> arityInfo + arityInfo.Length = curriedArgs.Length ) && (* no tailcall out of exception handler, etc. *) (match sequelIgnoringEndScopesAndDiscard sequel with Return | ReturnVoid -> true | _ -> false)) | None -> false -> let (kind, mark) = ListAssoc.find g.valRefEq v eenv.innerVals // already checked above in when guard - let ntmargs = - match kind with - | BranchCallClosure arityInfo -> - let ntmargs = List.foldBack (+) arityInfo 0 - GenExprs cenv cgbuf eenv args - ntmargs - | BranchCallMethod (arityInfo, curriedArgInfos, _, ntmargs, numObjArgs) -> - assert (curriedArgInfos.Length = arityInfo.Length ) - assert (curriedArgInfos.Length = args.Length) - //assert (curriedArgInfos.Length = ntmargs ) - GenUntupledArgsDiscardingLoneUnit cenv cgbuf eenv m numObjArgs curriedArgInfos args - if v.IsExtensionMember then - match curriedArgInfos, args with - | [[]], [_] when numObjArgs = 0 -> (ntmargs-1) - | [[_];[]], [_;_] when numObjArgs = 1 -> (ntmargs-1) - | _ -> ntmargs - else ntmargs - - for i = ntmargs - 1 downto 0 do - CG.EmitInstrs cgbuf (pop 1) Push0 [ I_starg (uint16 (i+cgbuf.PreallocatedArgCount)) ] + + // Generate the arguments for the direct tail call. + // We push all the arguments on the IL stack then write them back to the argument slots using + // I_starg. This seems a little sloppy, we could generate-then-write for each of the arguments. + // + // The arguments pushed don't include the 'this' argument for a recursive closure call (in PreallocatedArgCount) + // The arguments _do_ include the 'this' argument for instance method calls. The arguments do _not_ include witness arguments. + match kind with + | BranchCallClosure arityInfo -> + GenExprs cenv cgbuf eenv curriedArgs + + let numArgs = List.sum arityInfo + + // TODO: witness argument generation for closures + for i = numArgs - 1 downto 0 do + CG.EmitInstrs cgbuf (pop 1) Push0 [ I_starg (uint16 (cgbuf.PreallocatedArgCount+i)) ] + + | BranchCallMethod (arityInfo, curriedArgInfos, _, numObjArgs, numWitnessArgs, numMethodArgs) -> + assert (curriedArgInfos.Length = arityInfo.Length ) + assert (curriedArgInfos.Length = curriedArgs.Length) + + //assert (curriedArgInfos.Length = numArgs ) + // NOTE: we are not generating the witness arguments here + GenUntupledArgsDiscardingLoneUnit cenv cgbuf eenv m numObjArgs curriedArgInfos curriedArgs + + // Extension methods with empty arguments are evidently not quite in sufficiently normalized form, + // so apply a fixup here. This feels like a mistake associated with BindUnitVars, where that is not triggering + // in this case. + let numArgs = + if v.IsExtensionMember then + match curriedArgInfos, curriedArgs with + // static extension method with empty arguments. + | [[]], [_] when numObjArgs = 0 -> 0 + // instance extension method with empty arguments. + | [[_];[]], [_;_] when numObjArgs = 1 -> 0 + | _ -> numMethodArgs + else numMethodArgs + + for i = numArgs - 1 downto 0 do + CG.EmitInstrs cgbuf (pop 1) Push0 [ I_starg (uint16 (cgbuf.PreallocatedArgCount+numObjArgs+numWitnessArgs+i)) ] + + // Note, we don't reassign the witness arguments as these wont' have changed, because the type parameters aren't identical + + for i = numObjArgs - 1 downto 0 do + CG.EmitInstrs cgbuf (pop 1) Push0 [ I_starg (uint16 (cgbuf.PreallocatedArgCount+i)) ] CG.EmitInstrs cgbuf (pop 0) Push0 [ I_br mark.CodeLabel ] @@ -2944,8 +3047,8 @@ and GenApp cenv cgbuf eenv (f, fty, tyargs, args, m) sequel = let storage = StorageForValRef m vref eenv match storage with - | Method (_, _, mspec, _, _, _, _) -> - CG.EmitInstr cgbuf (pop 0) (Push [g.iltyp_RuntimeMethodHandle]) (I_ldtoken (ILToken.ILMethod mspec)) + | Method (_, _, mspec, _, _, _, _, _, _, _, _, _) -> + CG.EmitInstr cgbuf (pop 0) (Push [cenv.g.iltyp_RuntimeMethodHandle]) (I_ldtoken (ILToken.ILMethod mspec)) | _ -> errorR(Error(FSComp.SR.ilxgenUnexpectedArgumentToMethodHandleOfDuringCodegen(), m)) @@ -2971,28 +3074,34 @@ and GenApp cenv cgbuf eenv (f, fty, tyargs, args, m) sequel = when (let storage = StorageForValRef m vref eenv match storage with - | Method (topValInfo, vref, _, _, _, _, _) -> - (let tps, argtys, _, _ = GetTopValTypeInFSharpForm g topValInfo vref.Type m + | Method (topValInfo, vref, _, _, _, _, _, _, _, _, _, _) -> + (let tps, argtys, _, _ = GetTopValTypeInFSharpForm cenv.g topValInfo vref.Type m tps.Length = tyargs.Length && - argtys.Length <= args.Length) + argtys.Length <= curriedArgs.Length) | _ -> false) -> let storage = StorageForValRef m vref eenv match storage with - | Method (topValInfo, vref, mspec, _, _, _, _) -> - let nowArgs, laterArgs = - let _, curriedArgInfos, _, _ = GetTopValTypeInFSharpForm g topValInfo vref.Type m - List.splitAt curriedArgInfos.Length args + | Method (topValInfo, vref, mspec, mspecW, _, ctps, mtps, curriedArgInfos, _, _, _, _) -> + + let nowArgs, laterArgs = List.splitAt curriedArgInfos.Length curriedArgs + + let actualRetTy = applyTys cenv.g vref.Type (tyargs, nowArgs) + + let _, cxs, curriedArgInfos, returnTy, _ = GetTopValTypeInCompiledForm cenv.g topValInfo vref.Type m + + let mspec = + if not cenv.g.generateWitnesses || cxs.IsEmpty then + mspec + else + mspecW - let actualRetTy = applyTys g vref.Type (tyargs, nowArgs) - let _, curriedArgInfos, returnTy, _ = GetTopValTypeInCompiledForm g topValInfo vref.Type m let ilTyArgs = GenTypeArgs cenv.amap m eenv.tyenv tyargs - // For instance method calls chop off some type arguments, which are already - // carried by the class. Also work out if it's a virtual call. - let _, virtualCall, newobj, isSuperInit, isSelfInit, _, _, _ = GetMemberCallInfo g (vref, valUseFlags) in + // carried by the class. Also work out if it's a virtual call. + let _, virtualCall, newobj, isSuperInit, isSelfInit, _, _, _ = GetMemberCallInfo cenv.g (vref, valUseFlags) // numEnclILTypeArgs will include unit-of-measure args, unfortunately. For now, just cut-and-paste code from GetMemberCallInfo // @REVIEW: refactor this @@ -3007,6 +3116,7 @@ and GenApp cenv cgbuf eenv (f, fty, tyargs, args, m) sequel = List.splitAt numEnclILTypeArgs ilTyArgs let boxity = mspec.DeclaringType.Boxity + let mspec = mkILMethSpec (mspec.MethodRef, boxity, ilEnclArgTys, ilMethArgTys) // "Unit" return types on static methods become "void" @@ -3044,6 +3154,14 @@ and GenApp cenv cgbuf eenv (f, fty, tyargs, args, m) sequel = if isSuperInit || isSelfInit then CG.EmitInstrs cgbuf (pop 0) (Push [mspec.DeclaringType ]) [ mkLdarg0 ] + // We currently should never have any class-quantified witnesses + //assert cwitnesses.IsEmpty + if not cenv.g.generateWitnesses || cxs.IsEmpty then + () // not witness args + else + let _ctyargs, mtyargs = List.splitAt ctps.Length tyargs + GenWitnessArgs cenv cgbuf eenv m mtps mtyargs + GenUntupledArgsDiscardingLoneUnit cenv cgbuf eenv m vref.NumObjArgs curriedArgInfos nowArgs // Generate laterArgs (for effects) and save @@ -3090,13 +3208,13 @@ and GenApp cenv cgbuf eenv (f, fty, tyargs, args, m) sequel = // However, we know the type instantiation for the value. // In this case we can often generate a type-specific local expression for the value. // This reduces the number of dynamic type applications. - | (Expr.Val (vref, _, _), _, _) -> - GenGetValRefAndSequel cenv cgbuf eenv m vref (Some (tyargs, args, m, sequel)) + | (Expr.Val(vref, _, _), _, _) -> + GenGetValRefAndSequel cenv cgbuf eenv m vref (Some (tyargs, curriedArgs, m, sequel)) | _ -> (* worst case: generate a first-class function value and call *) GenExpr cenv cgbuf eenv SPSuppress f Continue - GenArgsAndIndirectCall cenv cgbuf eenv (fty, tyargs, args, m) sequel + GenCurriedArgsAndIndirectCall cenv cgbuf eenv (fty, tyargs, curriedArgs, m) sequel and CanTailcall (hasStructObjArg, ccallInfo, withinSEH, hasByrefArg, mustGenerateUnitAfterCall, isDllImport, isSelfInit, makesNoCriticalTailcalls, sequel) = @@ -3143,14 +3261,14 @@ and GenNamedLocalTyFuncCall cenv (cgbuf: CodeGenBuffer) eenv ty cloinfo tyargs m /// Generate an indirect call, converting to an ILX callfunc instruction -and GenArgsAndIndirectCall cenv cgbuf eenv (functy, tyargs, args, m) sequel = +and GenCurriedArgsAndIndirectCall cenv cgbuf eenv (functy, tyargs, curriedArgs, m) sequel = - // Generate the arguments to the indirect call - GenExprs cenv cgbuf eenv args - GenIndirectCall cenv cgbuf eenv (functy, tyargs, args, m) sequel + // Generate the curried arguments to the indirect call + GenExprs cenv cgbuf eenv curriedArgs + GenIndirectCall cenv cgbuf eenv (functy, tyargs, curriedArgs, m) sequel /// Generate an indirect call, converting to an ILX callfunc instruction -and GenIndirectCall cenv cgbuf eenv (functy, tyargs, args, m) sequel = +and GenIndirectCall cenv cgbuf eenv (functy, tyargs, curriedArgs, m) sequel = let g = cenv.g // Fold in the new types into the environment as we generate the formal types. @@ -3164,18 +3282,15 @@ and GenIndirectCall cenv cgbuf eenv (functy, tyargs, args, m) sequel = // This does two phases: REVIEW: the code is too complex for what it's achieving and should be rewritten let formalRetTy, appBuilder = - List.fold - (fun (formalFuncTy, sofar) _ -> - let dty, rty = destFunTy g formalFuncTy - (rty, (fun acc -> sofar (Apps_app(GenType cenv.amap m feenv dty, acc))))) - (formalFuncTy, id) - args + ((formalFuncTy, id), curriedArgs) ||> List.fold (fun (formalFuncTy, appBuilder) _ -> + let dty, rty = destFunTy cenv.g formalFuncTy + (rty, (fun acc -> appBuilder (Apps_app(GenType cenv.amap m feenv dty, acc))))) let ilxRetApps = Apps_done (GenType cenv.amap m feenv formalRetTy) List.foldBack (fun tyarg acc -> Apps_tyapp(GenType cenv.amap m eenv.tyenv tyarg, acc)) tyargs (appBuilder ilxRetApps) - let actualRetTy = applyTys g functy (tyargs, args) + let actualRetTy = applyTys cenv.g functy (tyargs, curriedArgs) let ilActualRetTy = GenType cenv.amap m eenv.tyenv actualRetTy // Check if any byrefs are involved to make sure we don't tailcall @@ -3191,8 +3306,8 @@ and GenIndirectCall cenv cgbuf eenv (functy, tyargs, args, m) sequel = CountCallFuncInstructions() // Generate the code code an ILX callfunc operation - let instrs = EraseClosures.mkCallFunc g.ilxPubCloEnv (fun ty -> cgbuf.AllocLocal([], ty, false) |> uint16) eenv.tyenv.Count isTailCall ilxClosureApps - CG.EmitInstrs cgbuf (pop (1+args.Length)) (Push [ilActualRetTy]) instrs + let instrs = EraseClosures.mkCallFunc cenv.g.ilxPubCloEnv (fun ty -> cgbuf.AllocLocal([], ty, false) |> uint16) eenv.tyenv.Count isTailCall ilxClosureApps + CG.EmitInstrs cgbuf (pop (1+curriedArgs.Length)) (Push [ilActualRetTy]) instrs // Done compiling indirect call... GenSequel cenv eenv.cloc cgbuf sequel @@ -3654,7 +3769,7 @@ and GenQuotation cenv cgbuf eenv (ast, conv, m, ety) sequel = | Some res -> res | None -> try - let qscope = QuotationTranslator.QuotationGenerationScope.Create (g, cenv.amap, cenv.viewCcu, QuotationTranslator.IsReflectedDefinition.No) + let qscope = QuotationTranslator.QuotationGenerationScope.Create (cenv.g, cenv.amap, cenv.viewCcu, cenv.tcVal, QuotationTranslator.IsReflectedDefinition.No) let astSpec = QuotationTranslator.ConvExprPublic qscope QuotationTranslator.QuotationTranslationEnv.Empty ast let referencedTypeDefs, spliceTypes, spliceArgExprs = qscope.Close() referencedTypeDefs, List.map fst spliceTypes, List.map fst spliceArgExprs, astSpec @@ -3670,17 +3785,16 @@ and GenQuotation cenv cgbuf eenv (ast, conv, m, ety) sequel = let bytesExpr = Expr.Op (TOp.Bytes astSerializedBytes, [], [], m) let deserializeExpr = - match QuotationTranslator.QuotationGenerationScope.ComputeQuotationFormat g with - | QuotationTranslator.QuotationSerializationFormat.FSharp_40_Plus -> - let referencedTypeDefExprs = List.map (mkILNonGenericBoxedTy >> mkTypeOfExpr cenv m) referencedTypeDefs - let referencedTypeDefsExpr = mkArray (g.system_Type_ty, referencedTypeDefExprs, m) - let spliceTypesExpr = mkArray (g.system_Type_ty, spliceTypeExprs, m) + let qf = QuotationTranslator.QuotationGenerationScope.ComputeQuotationFormat cenv.g + if qf.SupportsDeserializeEx then + let referencedTypeDefExprs = List.map (mkILNonGenericBoxedTy >> mkTypeOfExpr cenv m) referencedTypeDefs + let referencedTypeDefsExpr = mkArray (cenv.g.system_Type_ty, referencedTypeDefExprs, m) + let spliceTypesExpr = mkArray (cenv.g.system_Type_ty, spliceTypeExprs, m) let spliceArgsExpr = mkArray (rawTy, spliceArgExprs, m) - mkCallDeserializeQuotationFSharp40Plus g m someTypeInModuleExpr referencedTypeDefsExpr spliceTypesExpr spliceArgsExpr bytesExpr - - | QuotationTranslator.QuotationSerializationFormat.FSharp_20_Plus -> - let mkList ty els = List.foldBack (mkCons g ty) els (mkNil g m ty) - let spliceTypesExpr = mkList g.system_Type_ty spliceTypeExprs + mkCallDeserializeQuotationFSharp40Plus cenv.g m someTypeInModuleExpr referencedTypeDefsExpr spliceTypesExpr spliceArgsExpr bytesExpr + else + let mkList ty els = List.foldBack (mkCons cenv.g ty) els (mkNil cenv.g m ty) + let spliceTypesExpr = mkList cenv.g.system_Type_ty spliceTypeExprs let spliceArgsExpr = mkList rawTy spliceArgExprs mkCallDeserializeQuotationFSharp20Plus g m someTypeInModuleExpr spliceTypesExpr spliceArgsExpr bytesExpr @@ -3748,18 +3862,36 @@ and MakeNotSupportedExnExpr cenv eenv (argExpr, m) = let mref = mkILCtorMethSpecForTy(ilty, [g.ilg.typ_String]).MethodRef Expr.Op (TOp.ILCall (false, false, false, true, NormalValUse, false, false, mref, [], [], [ety]), [], [argExpr], m) -and GenTraitCall cenv cgbuf eenv (traitInfo, argExprs, m) expr sequel = +and GenTraitCall (cenv: cenv) cgbuf eenv (traitInfo: TraitConstraintInfo, argExprs, m) expr sequel = let g = cenv.g - let minfoOpt = CommitOperationResult (ConstraintSolver.CodegenWitnessThatTypeSupportsTraitConstraint cenv.TcVal g cenv.amap m traitInfo argExprs) - match minfoOpt with - | None -> - let exnArg = mkString g m (FSComp.SR.ilDynamicInvocationNotSupported(traitInfo.MemberName)) - let exnExpr = MakeNotSupportedExnExpr cenv eenv (exnArg, m) - let replacementExpr = mkThrow m (tyOfExpr g expr) exnExpr - GenExpr cenv cgbuf eenv SPSuppress replacementExpr sequel - | Some expr -> - let expr = cenv.optimizeDuringCodeGen expr - GenExpr cenv cgbuf eenv SPSuppress expr sequel + let inWitnessPassingScope = not eenv.witnessesInScope.IsEmpty + let witness = + if g.generateWitnesses && inWitnessPassingScope then + TryStorageForWitness eenv traitInfo.TraitKey + else + None + + match witness with + | Some storage -> + + let ty = GenWitnessTy g traitInfo.TraitKey + let argExprs = if argExprs.Length = 0 then [ mkUnit g m ] else argExprs + GenGetStorageAndSequel cenv cgbuf eenv m (ty, GenType cenv.amap m eenv.tyenv ty) storage (Some([], argExprs, m, sequel)) + + | None -> + // If witnesses are available, we should now always find trait witnesses in scope + assert not inWitnessPassingScope + + let minfoOpt = CommitOperationResult (ConstraintSolver.CodegenWitnessForTraitConstraint cenv.tcVal g cenv.amap m traitInfo argExprs) + match minfoOpt with + | None -> + let exnArg = mkString g m (FSComp.SR.ilDynamicInvocationNotSupported(traitInfo.MemberName)) + let exnExpr = MakeNotSupportedExnExpr cenv eenv (exnArg, m) + let replacementExpr = mkThrow m (tyOfExpr g expr) exnExpr + GenExpr cenv cgbuf eenv SPSuppress replacementExpr sequel + | Some expr -> + let expr = cenv.optimizeDuringCodeGen expr + GenExpr cenv cgbuf eenv SPSuppress expr sequel //-------------------------------------------------------------------------- // Generate byref-related operations @@ -3788,7 +3920,7 @@ and GenGetValAddr cenv cgbuf eenv (v: ValRef, m) sequel = let ilTy = if ilTy.IsNominal && ilTy.Boxity = ILBoxity.AsValue then ILType.Byref ilTy else ilTy EmitGetStaticFieldAddr cgbuf ilTy fspec - | Env (_, _, ilField, _) -> + | Env (_, ilField, _) -> CG.EmitInstrs cgbuf (pop 0) (Push [ILType.Byref ilTy]) [ mkLdarg0; mkNormalLdflda ilField ] | Local (_, _, Some _) | StaticProperty _ | Method _ | Env _ | Null -> @@ -4037,16 +4169,14 @@ and GenObjectExpr cenv cgbuf eenvouter expr (baseType, baseValOpt, basecall, ove let cloinfo, _, eenvinner = GetIlxClosureInfo cenv m false None eenvouter expr let cloAttribs = cloinfo.cloAttribs - let cloFreeVars = cloinfo.cloFreeVars let ilCloLambdas = cloinfo.ilCloLambdas let cloName = cloinfo.cloName - let ilxCloSpec = cloinfo.cloSpec - let ilCloFreeVars = cloinfo.cloILFreeVars + let ilCloAllFreeVars = cloinfo.ilCloAllFreeVars let ilCloGenericFormals = cloinfo.cloILGenericParams assert (isNil cloinfo.localTypeFuncDirectILGenericParams) let ilCloGenericActuals = cloinfo.cloSpec.GenericArgs - let ilCloRetTy = cloinfo.cloILFormalRetTy + let ilCloRetTy = cloinfo.ilCloFormalReturnTy let ilCloTypeRef = cloinfo.cloSpec.TypeRef let ilTyForOverriding = mkILBoxedTy ilCloTypeRef ilCloGenericActuals @@ -4073,13 +4203,11 @@ and GenObjectExpr cenv cgbuf eenvouter expr (baseType, baseValOpt, basecall, ove let attrs = GenAttrs cenv eenvinner cloAttribs let super = (if isInterfaceTy g baseType then g.ilg.typ_Object else ilCloRetTy) let interfaceTys = interfaceTys @ (if isInterfaceTy g baseType then [ilCloRetTy] else []) - let cloTypeDefs = GenClosureTypeDefs cenv (ilCloTypeRef, ilCloGenericFormals, attrs, ilCloFreeVars, ilCloLambdas, ilCtorBody, mdefs, mimpls, super, interfaceTys) + let cloTypeDefs = GenClosureTypeDefs cenv (ilCloTypeRef, ilCloGenericFormals, attrs, ilCloAllFreeVars, ilCloLambdas, ilCtorBody, mdefs, mimpls, super, interfaceTys) for cloTypeDef in cloTypeDefs do cgbuf.mgbuf.AddTypeDef(ilCloTypeRef, cloTypeDef, false, false, None) - CountClosure() - GenGetLocalVals cenv cgbuf eenvouter m cloFreeVars - CG.EmitInstr cgbuf (pop ilCloFreeVars.Length) (Push [ EraseClosures.mkTyOfLambdas g.ilxPubCloEnv ilCloLambdas]) (I_newobj (ilxCloSpec.Constructor, None)) + GenClosureAlloc cenv cgbuf eenvouter (cloinfo, m) GenSequel cenv eenvouter.cloc cgbuf sequel and GenSequenceExpr @@ -4097,7 +4225,7 @@ and GenSequenceExpr eenvouter |> AddStorageForLocalVals g (stateVars |> List.map (fun v -> v.Deref, Local(0, false, None))) // Get the free variables. Make a lambda to pretend that the 'nextEnumeratorValRef' is bound (it is an argument to GenerateNext) - let (cloAttribs, _, _, cloFreeTyvars, cloFreeVars, ilCloTypeRef: ILTypeRef, ilCloFreeVars, eenvinner) = + let (cloAttribs, _, _, cloFreeTyvars, cloWitnessInfos, cloFreeVars, ilCloTypeRef: ILTypeRef, ilCloAllFreeVars, eenvinner) = GetIlxClosureFreeVars cenv m None eenvouter [] (mkLambda m nextEnumeratorValRef.Deref (generateNextExpr, g.int32_ty)) let ilCloSeqElemTy = GenType cenv.amap m eenvinner.tyenv seqElemTy @@ -4112,7 +4240,7 @@ and GenSequenceExpr // Create a new closure class with a single "MoveNext" method that implements the iterator. let ilCloTyInner = mkILFormalBoxedTy ilCloTypeRef ilCloGenericParams let ilCloLambdas = Lambdas_return ilCloRetTyInner - let cloref = IlxClosureRef(ilCloTypeRef, ilCloLambdas, ilCloFreeVars) + let cloref = IlxClosureRef(ilCloTypeRef, ilCloLambdas, ilCloAllFreeVars) let ilxCloSpec = IlxClosureSpec.Create(cloref, GenGenericArgs m eenvouter.tyenv cloFreeTyvars) let formalClospec = IlxClosureSpec.Create(cloref, mkILFormalGenericArgs 0 ilCloGenericParams) @@ -4121,13 +4249,14 @@ and GenSequenceExpr CodeGenMethod cenv cgbuf.mgbuf ([], "GetFreshEnumerator", eenvinner, 1, (fun cgbuf eenv -> + GenWitnessArgsFromInfos cenv cgbuf eenv m cloWitnessInfos for fv in cloFreeVars do - /// State variables always get zero-initialized + // State variables always get zero-initialized if stateVarsSet.Contains fv then GenDefaultValue cenv cgbuf eenv (fv.Type, m) else GenGetLocalVal cenv cgbuf eenv m fv None - CG.EmitInstr cgbuf (pop ilCloFreeVars.Length) (Push [ilCloRetTyInner]) (I_newobj (formalClospec.Constructor, None)) + CG.EmitInstr cgbuf (pop ilCloAllFreeVars.Length) (Push [ilCloRetTyInner]) (I_newobj (formalClospec.Constructor, None)) GenSequel cenv eenv.cloc cgbuf Return), m) mkILNonGenericVirtualMethod("GetFreshEnumerator", ILMemberAccess.Public, [], mkILReturn ilCloEnumeratorTy, MethodBody.IL mbody) @@ -4164,13 +4293,14 @@ and GenSequenceExpr mkILSimpleStorageCtor(None, Some ilCloBaseTy.TypeSpec, ilCloTyInner, [], [], ILMemberAccess.Assembly).MethodBody let attrs = GenAttrs cenv eenvinner cloAttribs - let cloTypeDefs = GenClosureTypeDefs cenv (ilCloTypeRef, ilCloGenericParams, attrs, ilCloFreeVars, ilCloLambdas, ilCtorBody, [generateNextMethod;closeMethod;checkCloseMethod;lastGeneratedMethod;getFreshMethod], [], ilCloBaseTy, []) + let cloTypeDefs = GenClosureTypeDefs cenv (ilCloTypeRef, ilCloGenericParams, attrs, ilCloAllFreeVars, ilCloLambdas, ilCtorBody, [generateNextMethod;closeMethod;checkCloseMethod;lastGeneratedMethod;getFreshMethod], [], ilCloBaseTy, []) for cloTypeDef in cloTypeDefs do cgbuf.mgbuf.AddTypeDef(ilCloTypeRef, cloTypeDef, false, false, None) CountClosure() + GenWitnessArgsFromInfos cenv cgbuf eenvouter m cloWitnessInfos for fv in cloFreeVars do /// State variables always get zero-initialized if stateVarsSet.Contains fv then @@ -4178,16 +4308,16 @@ and GenSequenceExpr else GenGetLocalVal cenv cgbuf eenvouter m fv None - CG.EmitInstr cgbuf (pop ilCloFreeVars.Length) (Push [ilCloRetTyOuter]) (I_newobj (ilxCloSpec.Constructor, None)) + CG.EmitInstr cgbuf (pop ilCloAllFreeVars.Length) (Push [ilCloRetTyOuter]) (I_newobj (ilxCloSpec.Constructor, None)) GenSequel cenv eenvouter.cloc cgbuf sequel /// Generate the class for a closure type definition -and GenClosureTypeDefs cenv (tref: ILTypeRef, ilGenParams, attrs, ilCloFreeVars, ilCloLambdas, ilCtorBody, mdefs, mimpls, ext, ilIntfTys) = +and GenClosureTypeDefs cenv (tref: ILTypeRef, ilGenParams, attrs, ilCloAllFreeVars, ilCloLambdas, ilCtorBody, mdefs, mimpls, ext, ilIntfTys) = let g = cenv.g let cloInfo = - { cloFreeVars=ilCloFreeVars + { cloFreeVars=ilCloAllFreeVars cloStructure=ilCloLambdas cloCode=notlazy ilCtorBody } @@ -4232,12 +4362,12 @@ and GenLambdaClosure cenv (cgbuf: CodeGenBuffer) eenv isLocalTypeFunc selfv expr let cloinfo, body, eenvinner = GetIlxClosureInfo cenv m isLocalTypeFunc selfv eenv expr - let entryPointInfo = + let tailCallInfo = match selfv with | Some v -> [(v, BranchCallClosure (cloinfo.cloArityInfo))] | _ -> [] - let ilCloBody = CodeGenMethodForExpr cenv cgbuf.mgbuf (SPAlways, entryPointInfo, cloinfo.cloName, eenvinner, 1, body, Return) + let ilCloBody = CodeGenMethodForExpr cenv cgbuf.mgbuf (SPAlways, tailCallInfo, cloinfo.cloName, eenvinner, 1, body, Return) let ilCloTypeRef = cloinfo.cloSpec.TypeRef let cloTypeDefs = if isLocalTypeFunc then @@ -4279,12 +4409,12 @@ and GenLambdaClosure cenv (cgbuf: CodeGenBuffer) eenv isLocalTypeFunc selfv expr cgbuf.mgbuf.AddTypeDef(ilContractTypeRef, ilContractTypeDef, false, false, None) let ilCtorBody = mkILMethodBody (true, [], 8, nonBranchingInstrsToCode (mkCallBaseConstructor(ilContractTy, [])), None ) - let cloMethods = [ mkILGenericVirtualMethod("DirectInvoke", ILMemberAccess.Assembly, cloinfo.localTypeFuncDirectILGenericParams, [], mkILReturn (cloinfo.cloILFormalRetTy), MethodBody.IL ilCloBody) ] - let cloTypeDefs = GenClosureTypeDefs cenv (ilCloTypeRef, cloinfo.cloILGenericParams, [], cloinfo.cloILFreeVars, cloinfo.ilCloLambdas, ilCtorBody, cloMethods, [], ilContractTy, []) + let cloMethods = [ mkILGenericVirtualMethod("DirectInvoke", ILMemberAccess.Assembly, cloinfo.localTypeFuncDirectILGenericParams, [], mkILReturn (cloinfo.ilCloFormalReturnTy), MethodBody.IL ilCloBody) ] + let cloTypeDefs = GenClosureTypeDefs cenv (ilCloTypeRef, cloinfo.cloILGenericParams, [], cloinfo.ilCloAllFreeVars, cloinfo.ilCloLambdas, ilCtorBody, cloMethods, [], ilContractTy, []) cloTypeDefs else - GenClosureTypeDefs cenv (ilCloTypeRef, cloinfo.cloILGenericParams, [], cloinfo.cloILFreeVars, cloinfo.ilCloLambdas, ilCloBody, [], [], g.ilg.typ_Object, []) + GenClosureTypeDefs cenv (ilCloTypeRef, cloinfo.cloILGenericParams, [], cloinfo.ilCloAllFreeVars, cloinfo.ilCloLambdas, ilCloBody, [], [], g.ilg.typ_Object, []) CountClosure() for cloTypeDef in cloTypeDefs do cgbuf.mgbuf.AddTypeDef(ilCloTypeRef, cloTypeDef, false, false, None) @@ -4292,17 +4422,19 @@ and GenLambdaClosure cenv (cgbuf: CodeGenBuffer) eenv isLocalTypeFunc selfv expr | _ -> failwith "GenLambda: not a lambda" -and GenLambdaVal cenv (cgbuf: CodeGenBuffer) eenv (cloinfo, m) = +and GenClosureAlloc cenv (cgbuf: CodeGenBuffer) eenv (cloinfo, m) = let g = cenv.g + CountClosure() + GenWitnessArgsFromInfos cenv cgbuf eenv m cloinfo.cloWitnessInfos GenGetLocalVals cenv cgbuf eenv m cloinfo.cloFreeVars CG.EmitInstr cgbuf - (pop cloinfo.cloILFreeVars.Length) + (pop cloinfo.ilCloAllFreeVars.Length) (Push [EraseClosures.mkTyOfLambdas g.ilxPubCloEnv cloinfo.ilCloLambdas]) (I_newobj (cloinfo.cloSpec.Constructor, None)) and GenLambda cenv cgbuf eenv isLocalTypeFunc selfv expr sequel = let cloinfo, m = GenLambdaClosure cenv cgbuf eenv isLocalTypeFunc selfv expr - GenLambdaVal cenv cgbuf eenv (cloinfo, m) + GenClosureAlloc cenv cgbuf eenv (cloinfo, m) GenSequel cenv eenv.cloc cgbuf sequel and GenTypeOfVal cenv eenv (v: Val) = @@ -4312,7 +4444,7 @@ and GenFreevar cenv m eenvouter tyenvinner (fv: Val) = let g = cenv.g match StorageForVal m fv eenvouter with // Local type functions - | Local(_, _, Some _) | Env(_, _, _, Some _) -> g.ilg.typ_Object + | Local(_, _, Some _) | Env(_, _, Some _) -> g.ilg.typ_Object #if DEBUG // Check for things that should never make it into the free variable set. Only do this in debug for performance reasons | (StaticField _ | StaticProperty _ | Method _ | Null) -> error(InternalError("GenFreevar: compiler error: unexpected unrealized value", fv.Range)) @@ -4390,28 +4522,62 @@ and GetIlxClosureFreeVars cenv m selfv eenvouter takenNames expr = // If generating a named closure, add the closure itself as a var, available via "arg0" . // The latter doesn't apply for the delegate implementation of closures. // Build the environment that is active inside the closure itself - let eenvinner = eenvinner |> AddStorageForLocalVals g (match selfv with | Some v -> [(v.Deref, Arg 0)] | _ -> []) + let selfVars = match selfv with | Some v -> [(v.Deref, Arg 0)] | _ -> [] + let eenvinner = eenvinner |> AddStorageForLocalVals g selfVars + + // Work out if the closure captures any witnesses. + let cloWitnessInfos = + let inWitnessPassingScope = not eenvouter.witnessesInScope.IsEmpty + if g.generateWitnesses && inWitnessPassingScope then + GetTraitWitnessInfosOfTypars g [] cloFreeTyvars + else + [] + + let ilCloWitnessFreeVars, ilCloWitnessStorage = + let names = + cloWitnessInfos + |> List.map (fun w -> String.uncapitalize w.MemberName) + |> ChooseFreeVarNames takenNames + (cloWitnessInfos, names) + ||> List.map2 (fun w nm -> + let ty = GenWitnessTy cenv.g w + let ilTy = GenType cenv.amap m eenvinner.tyenv ty + let ilFv = mkILFreeVar (nm, true, ilTy) + let storage = + let ilField = mkILFieldSpecInTy (ilCloTyInner, ilFv.fvName, ilFv.fvType) + Env(ilCloTyInner, ilField, None) + ilFv, (w, storage)) + |> List.unzip + + // Allocate storage in the environment for the witnesses + let eenvinner = eenvinner |> AddStorageForLocalWitnesses ilCloWitnessStorage - let ilCloFreeVars = - let ilCloFreeVarNames = ChooseFreeVarNames takenNames (List.map nameOfVal cloFreeVars) - let ilCloFreeVars = (cloFreeVars, ilCloFreeVarNames) ||> List.map2 (fun fv nm -> mkILFreeVar (nm, fv.IsCompilerGenerated, GenFreevar cenv m eenvouter eenvinner.tyenv fv)) - ilCloFreeVars + let ilCloFreeVars, ilCloFreeVarStorage = + let names = + cloFreeVars + |> List.map nameOfVal + |> ChooseFreeVarNames takenNames - let ilCloFreeVarStorage = - (cloFreeVars, ilCloFreeVars) ||> List.mapi2 (fun i v fv -> + (cloFreeVars, names) + ||> List.map2 (fun fv nm -> let localCloInfo = - match StorageForVal m v eenvouter with + match StorageForVal m fv eenvouter with | Local(_, _, localCloInfo) - | Env(_, _, _, localCloInfo) -> localCloInfo + | Env(_, _, localCloInfo) -> localCloInfo | _ -> None - let ilField = mkILFieldSpecInTy (ilCloTyInner, fv.fvName, fv.fvType) + let ilFv = mkILFreeVar (nm, fv.IsCompilerGenerated, GenFreevar cenv m eenvouter eenvinner.tyenv fv) + let storage = + let ilField = mkILFieldSpecInTy (ilCloTyInner, ilFv.fvName, ilFv.fvType) + Env(ilCloTyInner, ilField, localCloInfo) + ilFv, (fv, storage)) + |> List.unzip - (v, Env(ilCloTyInner, i, ilField, localCloInfo))) + let ilCloAllFreeVars = Array.ofList (ilCloWitnessFreeVars @ ilCloFreeVars) let eenvinner = eenvinner |> AddStorageForLocalVals g ilCloFreeVarStorage // Return a various results - (cloAttribs, cloInternalFreeTyvars, cloContractFreeTyvars, cloFreeTyvars, cloFreeVars, ilCloTypeRef, Array.ofList ilCloFreeVars, eenvinner) + (cloAttribs, cloInternalFreeTyvars, cloContractFreeTyvars, cloFreeTyvars, cloWitnessInfos, cloFreeVars, ilCloTypeRef, ilCloAllFreeVars, eenvinner) and GetIlxClosureInfo cenv m isLocalTypeFunc selfv eenvouter expr = @@ -4441,21 +4607,22 @@ and GetIlxClosureInfo cenv m isLocalTypeFunc selfv eenvouter expr = let takenNames = vs |> List.map (fun v -> v.CompiledName) // Get the free variables and the information about the closure, add the free variables to the environment - let (cloAttribs, cloInternalFreeTyvars, cloContractFreeTyvars, _, cloFreeVars, ilCloTypeRef, ilCloFreeVars, eenvinner) = GetIlxClosureFreeVars cenv m selfv eenvouter takenNames expr + let (cloAttribs, cloInternalFreeTyvars, cloContractFreeTyvars, cloFreeTyvars, cloWitnessInfos, cloFreeVars, ilCloTypeRef, ilCloAllFreeVars, eenvinner) = + GetIlxClosureFreeVars cenv m selfv eenvouter takenNames expr // Put the type and value arguments into the environment - let rec getClosureArgs eenv ntmargs tvsl (vs: Val list) = + let rec getClosureArgs eenv numArgs tvsl (vs: Val list) = match tvsl, vs with | tvs :: rest, _ -> let eenv = AddTyparsToEnv tvs eenv - let l, eenv = getClosureArgs eenv ntmargs rest vs + let l, eenv = getClosureArgs eenv numArgs rest vs let lambdas = (tvs, l) ||> List.foldBack (fun tv sofar -> Lambdas_forall(GenGenericParam cenv eenv tv, sofar)) lambdas, eenv | [], v :: rest -> let nm = v.CompiledName let l, eenv = - let eenv = AddStorageForVal g (v, notlazy (Arg ntmargs)) eenv - getClosureArgs eenv (ntmargs+1) [] rest + let eenv = AddStorageForVal g (v, notlazy (Arg numArgs)) eenv + getClosureArgs eenv (numArgs+1) [] rest let lambdas = Lambdas_lambda (mkILParamNamed(nm, GenTypeOfVal cenv eenv v), l) lambdas, eenv | _ -> @@ -4516,7 +4683,7 @@ and GetIlxClosureInfo cenv m isLocalTypeFunc selfv eenvouter expr = let ilCloGenericFormals = ilContractGenericParams @ ilInternalGenericParams let ilCloGenericActuals = ilContractGenericActuals @ ilInternalGenericActuals - let ilDirectGenericParams, ilReturnTy, ilCloLambdas = + let ilDirectGenericParams, ilCloReturnTy, ilCloLambdas = if isLocalTypeFunc then let rec strip lambdas acc = match lambdas with @@ -4528,17 +4695,19 @@ and GetIlxClosureInfo cenv m isLocalTypeFunc selfv eenvouter expr = [], ilReturnTy, ilCloLambdas - let ilxCloSpec = IlxClosureSpec.Create(IlxClosureRef(ilCloTypeRef, ilCloLambdas, ilCloFreeVars), ilCloGenericActuals) + let ilxCloSpec = IlxClosureSpec.Create(IlxClosureRef(ilCloTypeRef, ilCloLambdas, ilCloAllFreeVars), ilCloGenericActuals) let cloinfo = { cloExpr=expr cloName=ilCloTypeRef.Name cloArityInfo =narginfo ilCloLambdas=ilCloLambdas - cloILFreeVars = ilCloFreeVars - cloILFormalRetTy=ilReturnTy + ilCloAllFreeVars = ilCloAllFreeVars + ilCloFormalReturnTy = ilCloReturnTy cloSpec = ilxCloSpec cloILGenericParams = ilCloGenericFormals cloFreeVars=cloFreeVars + cloFreeTyvars=cloFreeTyvars + cloWitnessInfos = cloWitnessInfos cloAttribs=cloAttribs localTypeFuncContractFreeTypars = cloContractFreeTyvars localTypeFuncInternalFreeTypars = cloInternalFreeTyvars @@ -4598,7 +4767,9 @@ and GenDelegateExpr cenv cgbuf eenvouter expr (TObjExprMethod((TSlotSig(_, deleg // Work out the free type variables for the morphing thunk let takenNames = List.map nameOfVal tmvs - let (cloAttribs, _, _, cloFreeTyvars, cloFreeVars, ilDelegeeTypeRef, ilCloFreeVars, eenvinner) = GetIlxClosureFreeVars cenv m None eenvouter takenNames expr + let (cloAttribs, _, _, cloFreeTyvars, cloWitnessInfos, cloFreeVars, ilDelegeeTypeRef, ilCloAllFreeVars, eenvinner) = + GetIlxClosureFreeVars cenv m None eenvouter takenNames expr + let ilDelegeeGenericParams = GenGenericParams cenv eenvinner cloFreeTyvars let ilDelegeeGenericActualsInner = mkILFormalGenericArgs 0 ilDelegeeGenericParams @@ -4628,15 +4799,18 @@ and GenDelegateExpr cenv cgbuf eenvouter expr (TObjExprMethod((TSlotSig(_, deleg let ilCloLambdas = Lambdas_return ilCtxtDelTy let ilAttribs = GenAttrs cenv eenvinner cloAttribs - let cloTypeDefs = GenClosureTypeDefs cenv (ilDelegeeTypeRef, ilDelegeeGenericParams, ilAttribs, ilCloFreeVars, ilCloLambdas, ilCtorBody, [delegeeInvokeMeth], [], g.ilg.typ_Object, []) + let cloTypeDefs = GenClosureTypeDefs cenv (ilDelegeeTypeRef, ilDelegeeGenericParams, ilAttribs, ilCloAllFreeVars, ilCloLambdas, ilCtorBody, [delegeeInvokeMeth], [], g.ilg.typ_Object, []) for cloTypeDef in cloTypeDefs do cgbuf.mgbuf.AddTypeDef(ilDelegeeTypeRef, cloTypeDef, false, false, None) CountClosure() let ctxtGenericArgsForDelegee = GenGenericArgs m eenvouter.tyenv cloFreeTyvars - let ilxCloSpec = IlxClosureSpec.Create(IlxClosureRef(ilDelegeeTypeRef, ilCloLambdas, ilCloFreeVars), ctxtGenericArgsForDelegee) + let ilxCloSpec = IlxClosureSpec.Create(IlxClosureRef(ilDelegeeTypeRef, ilCloLambdas, ilCloAllFreeVars), ctxtGenericArgsForDelegee) + + GenWitnessArgsFromInfos cenv cgbuf eenvouter m cloWitnessInfos GenGetLocalVals cenv cgbuf eenvouter m cloFreeVars - CG.EmitInstr cgbuf (pop ilCloFreeVars.Length) (Push [EraseClosures.mkTyOfLambdas g.ilxPubCloEnv ilCloLambdas]) (I_newobj (ilxCloSpec.Constructor, None)) + + CG.EmitInstr cgbuf (pop ilCloAllFreeVars.Length) (Push [EraseClosures.mkTyOfLambdas g.ilxPubCloEnv ilCloLambdas]) (I_newobj (ilxCloSpec.Constructor, None)) let ilDelegeeTyOuter = mkILBoxedTy ilDelegeeTypeRef ctxtGenericArgsForDelegee let ilDelegeeInvokeMethOuter = mkILNonGenericInstanceMethSpecInTy (ilDelegeeTyOuter, "Invoke", typesOfILParams ilDelegeeParams, ilDelegeeRet.Type) @@ -4647,9 +4821,26 @@ and GenDelegateExpr cenv cgbuf eenvouter expr (TObjExprMethod((TSlotSig(_, deleg /// Generate statically-resolved conditionals used for type-directed optimizations. and GenStaticOptimization cenv cgbuf eenv (constraints, e2, e3, _m) sequel = + // Note: during IlxGen, even if answer is StaticOptimizationAnswer.Unknown we discard the static optimization + // This means 'when ^T : ^T' is discarded if not resolved. + // + // This doesn't apply when witnesses are available. In that case, "when ^T : ^T" is resolved as 'Yes', + // this is because all the uses of "when ^T : ^T" in FSharp.Core (e.g. for are for deciding between the + // witness-based implementation and the legacy dynamic implementation, e.g. + // + // let inline ( * ) (x: ^T) (y: ^U) : ^V = + // MultiplyDynamic<(^T),(^U),(^V)> x y + // ... + // when ^T : ^T = ((^T or ^U): (static member (*) : ^T * ^U -> ^V) (x,y)) + // + // When witnesses are not available we use the dynamic implementation. + let e = - if DecideStaticOptimizations cenv.g constraints = StaticOptimizationAnswer.Yes then e2 - else e3 + let inWitnessPassingScope = not eenv.witnessesInScope.IsEmpty + if DecideStaticOptimizations cenv.g constraints inWitnessPassingScope = StaticOptimizationAnswer.Yes then + e2 + else + e3 GenExpr cenv cgbuf eenv SPSuppress e sequel //------------------------------------------------------------------------- @@ -5086,7 +5277,7 @@ and GenLetRecBindings cenv (cgbuf: CodeGenBuffer) eenv (allBinds: Bindings, m) = clo.cloFreeVars |> List.iter (fun fv -> if Zset.contains fv forwardReferenceSet then match StorageForVal m fv eenvclo with - | Env (_, _, ilField, _) -> fixups := (boundv, fv, (fun () -> GenLetRecFixup cenv cgbuf eenv (clo.cloSpec, access, ilField, exprForVal m fv, m))) :: !fixups + | Env (_, ilField, _) -> fixups := (boundv, fv, (fun () -> GenLetRecFixup cenv cgbuf eenv (clo.cloSpec, access, ilField, exprForVal m fv, m))) :: !fixups | _ -> error (InternalError("GenLetRec: " + fv.LogicalName + " was not in the environment", m)) ) | Expr.Val (vref, _, _) -> @@ -5189,11 +5380,22 @@ and GenBindingAfterSequencePoint cenv cgbuf eenv sp (TBind(vspec, rhsExpr, _)) s CommitStartScope cgbuf startScopeMarkOpt GenExpr cenv cgbuf eenv SPSuppress cctorBody discard - | Method (topValInfo, _, mspec, _, paramInfos, methodArgTys, retInfo) -> - let tps, ctorThisValOpt, baseValOpt, vsl, body', bodyty = IteratedAdjustArityOfLambda g cenv.amap topValInfo rhsExpr - let methodVars = List.concat vsl + | Method (topValInfo, _, mspec, mspecW, _, ctps, mtps, curriedArgInfos, paramInfos, witnessInfos, argTys, retInfo) -> + + let methLambdaTypars, methLambdaCtorThisValOpt, methLambdaBaseValOpt, methLambdaCurriedVars, methLambdaBody, methLambdaBodyTy = + IteratedAdjustArityOfLambda cenv.g cenv.amap topValInfo rhsExpr + + let methLambdaVars = List.concat methLambdaCurriedVars + CommitStartScope cgbuf startScopeMarkOpt - GenMethodForBinding cenv cgbuf eenv (vspec, mspec, access, paramInfos, retInfo) (topValInfo, ctorThisValOpt, baseValOpt, tps, methodVars, methodArgTys, body', bodyty) + + GenMethodForBinding cenv cgbuf eenv (vspec, mspec, false, access, ctps, mtps, [], curriedArgInfos, paramInfos, argTys, retInfo, topValInfo, methLambdaCtorThisValOpt, methLambdaBaseValOpt, methLambdaTypars, methLambdaVars, methLambdaBody, methLambdaBodyTy) + + // If generating witnesses, then generate the second entry point with additional arguments. + // Take a copy of the expression to ensure generated names are unique. + if cenv.g.generateWitnesses && not witnessInfos.IsEmpty then + let copyOfLambdaBody = copyExpr cenv.g CloneAll methLambdaBody + GenMethodForBinding cenv cgbuf eenv (vspec, mspecW, true, access, ctps, mtps, witnessInfos, curriedArgInfos, paramInfos, argTys, retInfo, topValInfo, methLambdaCtorThisValOpt, methLambdaBaseValOpt, methLambdaTypars, methLambdaVars, copyOfLambdaBody, methLambdaBodyTy) | StaticProperty (ilGetterMethSpec, optShadowLocal) -> @@ -5469,59 +5671,67 @@ and GenParamAttribs cenv paramTy attribs = inFlag, outFlag, optionalFlag, defaultValue, Marshal, attribs /// Generate IL parameters -and GenParams cenv eenv (mspec: ILMethodSpec) (attribs: ArgReprInfo list) methodArgTys (implValsOpt: Val list option) = - let g = cenv.g - let ilArgTys = mspec.FormalArgTypes - let argInfosAndTypes = - if List.length attribs = List.length ilArgTys then List.zip ilArgTys attribs - else ilArgTys |> List.map (fun ilArgTy -> ilArgTy, ValReprInfo.unnamedTopArg1) +and GenParams cenv eenv m (mspec: ILMethodSpec) witnessInfos (argInfos: ArgReprInfo list) methArgTys (implValsOpt: Val list option) = + let ilWitnessParams = GenWitnessParams cenv eenv m witnessInfos + let ilArgTys = mspec.FormalArgTypes |> List.skip witnessInfos.Length - let argInfosAndTypes = + let ilArgTysAndInfos = + if argInfos.Length = ilArgTys.Length then + List.zip ilArgTys argInfos + else + assert false + ilArgTys |> List.map (fun ilArgTy -> ilArgTy, ValReprInfo.unnamedTopArg1) + + let ilArgTysAndInfoAndVals = match implValsOpt with | Some implVals when (implVals.Length = ilArgTys.Length) -> - List.map2 (fun x y -> x, Some y) argInfosAndTypes implVals + List.map2 (fun x y -> x, Some y) ilArgTysAndInfos implVals | _ -> - List.map (fun x -> x, None) argInfosAndTypes + List.map (fun x -> x, None) ilArgTysAndInfos - (Set.empty, List.zip methodArgTys argInfosAndTypes) - ||> List.mapFold (fun takenNames (methodArgTy, ((ilArgTy, topArgInfo), implValOpt)) -> - let inFlag, outFlag, optionalFlag, defaultParamValue, Marshal, attribs = GenParamAttribs cenv methodArgTy topArgInfo.Attribs + let ilParams, _ = + (Set.empty, List.zip methArgTys ilArgTysAndInfoAndVals) + ||> List.mapFold (fun takenNames (methodArgTy, ((ilArgTy, topArgInfo), implValOpt)) -> + let inFlag, outFlag, optionalFlag, defaultParamValue, Marshal, attribs = GenParamAttribs cenv methodArgTy topArgInfo.Attribs - let idOpt = (match topArgInfo.Name with - | Some v -> Some v - | None -> match implValOpt with - | Some v -> Some v.Id - | None -> None) - - let nmOpt, takenNames = - match idOpt with - | Some id -> - let nm = if takenNames.Contains(id.idText) then globalNng.FreshCompilerGeneratedName (id.idText, id.idRange) else id.idText - Some nm, takenNames.Add nm - | None -> - None, takenNames + let idOpt = + match topArgInfo.Name with + | Some v -> Some v + | None -> + match implValOpt with + | Some v -> Some v.Id + | None -> None + + let nmOpt, takenNames = + match idOpt with + | Some id -> + let nm = if takenNames.Contains(id.idText) then globalNng.FreshCompilerGeneratedName (id.idText, id.idRange) else id.idText + Some nm, takenNames.Add(nm) + | None -> + None, takenNames - let ilAttribs = GenAttrs cenv eenv attribs + let ilAttribs = GenAttrs cenv eenv attribs - let ilAttribs = - match GenReadOnlyAttributeIfNecessary g methodArgTy with - | Some attr -> ilAttribs @ [attr] - | None -> ilAttribs - - let param: ILParameter = - { Name=nmOpt - Type= ilArgTy - Default=defaultParamValue - Marshal=Marshal - IsIn=inFlag - IsOut=outFlag - IsOptional=optionalFlag - CustomAttrsStored = storeILCustomAttrs (mkILCustomAttrs ilAttribs) - MetadataIndex = NoMetadataIdx } - - param, takenNames) - |> fst + let ilAttribs = + match GenReadOnlyAttributeIfNecessary cenv.g methodArgTy with + | Some attr -> ilAttribs @ [attr] + | None -> ilAttribs + + let param : ILParameter = + { Name = nmOpt + Type = ilArgTy + Default = defaultParamValue + Marshal = Marshal + IsIn = inFlag + IsOut = outFlag + IsOptional = optionalFlag + CustomAttrsStored = storeILCustomAttrs (mkILCustomAttrs ilAttribs) + MetadataIndex = NoMetadataIdx } + + param, takenNames) + + ilWitnessParams @ ilParams /// Generate IL method return information and GenReturnInfo cenv eenv ilRetTy (retInfo: ArgReprInfo) : ILReturn = @@ -5562,42 +5772,52 @@ and GenEventForProperty cenv eenvForMeth (mspec: ILMethodSpec) (v: Val) ilAttrsT otherMethods= [], customAttrs = mkILCustomAttrs ilAttrsThatGoOnPrimaryItem) -and ComputeFlagFixupsForMemberBinding cenv (v: Val, memberInfo: ValMemberInfo) = - let g = cenv.g - if isNil memberInfo.ImplementedSlotSigs then - [fixupVirtualSlotFlags] - else - memberInfo.ImplementedSlotSigs |> List.map (fun slotsig -> - let oty = slotsig.ImplementedType - let otcref = tcrefOfAppTy g oty - let tcref = v.MemberApparentEntity - - let useMethodImpl = - // REVIEW: it would be good to get rid of this special casing of Compare and GetHashCode during code generation - isInterfaceTy g oty && - (let isCompare = - Option.isSome tcref.GeneratedCompareToValues && - (typeEquiv g oty g.mk_IComparable_ty || - tyconRefEq g g.system_GenericIComparable_tcref otcref) - - not isCompare) && - - (let isGenericEquals = - Option.isSome tcref.GeneratedHashAndEqualsWithComparerValues && tyconRefEq g g.system_GenericIEquatable_tcref otcref - - not isGenericEquals) && - (let isStructural = - (Option.isSome tcref.GeneratedCompareToWithComparerValues && typeEquiv g oty g.mk_IStructuralComparable_ty) || - (Option.isSome tcref.GeneratedHashAndEqualsWithComparerValues && typeEquiv g oty g.mk_IStructuralEquatable_ty) +and ComputeUseMethodImpl cenv (v: Val, slotsig: SlotSig) = + let oty = slotsig.ImplementedType + let otcref = tcrefOfAppTy cenv.g oty + let tcref = v.MemberApparentEntity + // REVIEW: it would be good to get rid of this special casing of Compare and GetHashCode during code generation + isInterfaceTy cenv.g oty && + (let isCompare = + Option.isSome tcref.GeneratedCompareToValues && + (typeEquiv cenv.g oty cenv.g.mk_IComparable_ty || + tyconRefEq cenv.g cenv.g.system_GenericIComparable_tcref otcref) + + not isCompare) && - not isStructural) + (let isGenericEquals = + Option.isSome tcref.GeneratedHashAndEqualsWithComparerValues && tyconRefEq cenv.g cenv.g.system_GenericIEquatable_tcref otcref + + not isGenericEquals) && + (let isStructural = + (Option.isSome tcref.GeneratedCompareToWithComparerValues && typeEquiv cenv.g oty cenv.g.mk_IStructuralComparable_ty) || + (Option.isSome tcref.GeneratedHashAndEqualsWithComparerValues && typeEquiv cenv.g oty cenv.g.mk_IStructuralEquatable_ty) - let nameOfOverridingMethod = GenNameOfOverridingMethod cenv (useMethodImpl, slotsig) + not isStructural) +and ComputeMethodImplNameFixupForMemberBinding cenv (v: Val, memberInfo: ValMemberInfo) = + if isNil memberInfo.ImplementedSlotSigs then + None + else + let slotsig = memberInfo.ImplementedSlotSigs |> List.last + let useMethodImpl = ComputeUseMethodImpl cenv (v, slotsig) + let nameOfOverridingMethod = GenNameOfOverridingMethod cenv (useMethodImpl, slotsig) + Some nameOfOverridingMethod + +and ComputeFlagFixupsForMemberBinding cenv (v: Val, memberInfo: ValMemberInfo) = + [ if isNil memberInfo.ImplementedSlotSigs then + yield fixupVirtualSlotFlags + else + for slotsig in memberInfo.ImplementedSlotSigs do + let useMethodImpl = ComputeUseMethodImpl cenv (v, slotsig) + if useMethodImpl then - fixupMethodImplFlags >> renameMethodDef nameOfOverridingMethod + yield fixupMethodImplFlags else - fixupVirtualSlotFlags >> renameMethodDef nameOfOverridingMethod) + yield fixupVirtualSlotFlags + match ComputeMethodImplNameFixupForMemberBinding cenv (v, memberInfo) with + | Some nm -> yield renameMethodDef nm + | None -> () ] and ComputeMethodImplAttribs cenv (_v: Val) attrs = let g = cenv.g @@ -5629,40 +5849,58 @@ and ComputeMethodImplAttribs cenv (_v: Val) attrs = and GenMethodForBinding cenv cgbuf eenv - (v: Val, mspec, access, paramInfos, retInfo) - (topValInfo, ctorThisValOpt, baseValOpt, tps, methodVars, methodArgTys, body, returnTy) = + (v: Val, mspec, hasWitnessArgs, access, ctps, mtps, witnessInfos, curriedArgInfos, paramInfos, argTys, retInfo, topValInfo, + ctorThisValOpt, baseValOpt, methLambdaTypars, methLambdaVars, methLambdaBody, returnTy) = let g = cenv.g let m = v.Range + let selfMethodVars, nonSelfMethodVars, compileAsInstance = match v.MemberInfo with - | Some _ when ValSpecIsCompiledAsInstance g v -> - match methodVars with + | Some _ when ValSpecIsCompiledAsInstance cenv.g v -> + match methLambdaVars with | [] -> error(InternalError("Internal error: empty argument list for instance method", v.Range)) - | h :: t -> [h], t, true - | _ -> [], methodVars, false + | h::t -> [h], t, true + | _ -> [], methLambdaVars, false - let nonUnitNonSelfMethodVars, body = BindUnitVars g (nonSelfMethodVars, paramInfos, body) - let nonUnitMethodVars = selfMethodVars@nonUnitNonSelfMethodVars - let cmtps, curriedArgInfos, _, _ = GetTopValTypeInCompiledForm g topValInfo v.Type v.Range + let nonUnitNonSelfMethodVars, body = BindUnitVars cenv.g (nonSelfMethodVars, paramInfos, methLambdaBody) let eenv = bindBaseOrThisVarOpt cenv eenv ctorThisValOpt let eenv = bindBaseOrThisVarOpt cenv eenv baseValOpt // The type parameters of the method's type are different to the type parameters // for the big lambda ("tlambda") of the implementation of the method. - let eenvUnderMethLambdaTypars = EnvForTypars tps eenv - let eenvUnderMethTypeTypars = EnvForTypars cmtps eenv + let eenvUnderMethLambdaTypars = EnvForTypars methLambdaTypars eenv + let eenvUnderMethTypeClassTypars = EnvForTypars ctps eenv + let eenvUnderMethTypeTypars = AddTyparsToEnv mtps eenvUnderMethTypeClassTypars // Add the arguments to the environment. We add an implicit 'this' argument to constructors let isCtor = v.IsConstructor + + let methLambdaWitnessInfos = + if hasWitnessArgs then + let methLambdaParentTypars, methLambdaMethTypars = List.splitAt ctps.Length methLambdaTypars + GetTraitWitnessInfosOfTypars cenv.g methLambdaParentTypars methLambdaMethTypars + else + [] + + // If this assert fails then there is a mismatch in the number of trait constraints on the method type and the number + // on the method implementation. + assert (methLambdaWitnessInfos.Length = witnessInfos.Length) + let eenvForMeth = let eenvForMeth = eenvUnderMethLambdaTypars - let numImplicitArgs = if isCtor then 1 else 0 - let eenvForMeth = AddStorageForLocalVals g (List.mapi (fun i v -> (v, Arg (numImplicitArgs+i))) nonUnitMethodVars) eenvForMeth + let numArgsUsed = 0 + let numArgsUsed = numArgsUsed + (if isCtor then 1 else 0) + let eenvForMeth = eenvForMeth |> AddStorageForLocalVals cenv.g (selfMethodVars |> List.mapi (fun i v -> (v, Arg (numArgsUsed+i)))) + let numArgsUsed = numArgsUsed + selfMethodVars.Length + let eenvForMeth = eenvForMeth |> AddStorageForLocalWitnesses (methLambdaWitnessInfos |> List.mapi (fun i w -> (w, Arg (numArgsUsed+i)))) + let numArgsUsed = numArgsUsed + methLambdaWitnessInfos.Length + let eenvForMeth = eenvForMeth |> AddStorageForLocalVals cenv.g (List.mapi (fun i v -> (v, Arg (numArgsUsed+i))) nonUnitNonSelfMethodVars) eenvForMeth - let tailCallInfo = [(mkLocalValRef v, BranchCallMethod (topValInfo.AritiesOfArgs, curriedArgInfos, tps, nonUnitMethodVars.Length, v.NumObjArgs))] + let tailCallInfo = + [(mkLocalValRef v, BranchCallMethod (topValInfo.AritiesOfArgs, curriedArgInfos, methLambdaTypars, selfMethodVars.Length, methLambdaWitnessInfos.Length, nonUnitNonSelfMethodVars.Length))] // Discard the result on a 'void' return type. For a constructor just return 'void' let sequel = @@ -5672,10 +5910,10 @@ and GenMethodForBinding // Now generate the code. let hasPreserveSigNamedArg, ilMethodBody, hasDllImport = - match TryFindFSharpAttributeOpt g g.attrib_DllImportAttribute v.Attribs with - | Some (Attrib(_, _, [ AttribStringArg dll ], namedArgs, _, _, m)) -> - if not (isNil tps) then error(Error(FSComp.SR.ilSignatureForExternalFunctionContainsTypeParameters(), m)) - let hasPreserveSigNamedArg, mbody = GenPInvokeMethod (v.CompiledName, dll, namedArgs) + match TryFindFSharpAttributeOpt cenv.g cenv.g.attrib_DllImportAttribute v.Attribs with + | Some (Attrib(_, _, [ AttribStringArg(dll) ], namedArgs, _, _, m)) -> + if not (isNil methLambdaTypars) then error(Error(FSComp.SR.ilSignatureForExternalFunctionContainsTypeParameters(), m)) + let hasPreserveSigNamedArg, mbody = GenPInvokeMethod (mspec.Name, dll, namedArgs) hasPreserveSigNamedArg, mbody, true | Some (Attrib(_, _, _, _, _, _, m)) -> @@ -5683,10 +5921,13 @@ and GenMethodForBinding | _ -> // Replace the body of ValInline.PseudoVal "must inline" methods with a 'throw' - // However still generate the code for reflection etc. + // For witness-passing methods, don't do this is `isLegacy` flag specified + // on the attribute. let bodyExpr = - if HasFSharpAttribute g g.attrib_NoDynamicInvocationAttribute v.Attribs then - let exnArg = mkString g m (FSComp.SR.ilDynamicInvocationNotSupported(v.CompiledName)) + let attr = TryFindFSharpBoolAttributeAssumeFalse cenv.g cenv.g.attrib_NoDynamicInvocationAttribute v.Attribs + if (not hasWitnessArgs && attr.IsSome) || + (hasWitnessArgs && attr = Some false) then + let exnArg = mkString cenv.g m (FSComp.SR.ilDynamicInvocationNotSupported(mspec.Name)) let exnExpr = MakeNotSupportedExnExpr cenv eenv (exnArg, m) mkThrow m returnTy exnExpr else @@ -5727,105 +5968,107 @@ and GenMethodForBinding [ yield! GenAttrs cenv eenv attrs yield! GenCompilationArgumentCountsAttr cenv v ] - let ilTypars = GenGenericParams cenv eenvUnderMethLambdaTypars tps - let ilParams = GenParams cenv eenv mspec paramInfos methodArgTys (Some nonUnitNonSelfMethodVars) - let ilReturn = GenReturnInfo cenv eenv mspec.FormalReturnType retInfo + let ilTypars = GenGenericParams cenv eenvUnderMethLambdaTypars methLambdaTypars + let ilParams = GenParams cenv eenvUnderMethTypeTypars m mspec witnessInfos paramInfos argTys (Some nonUnitNonSelfMethodVars) + let ilReturn = GenReturnInfo cenv eenvUnderMethTypeTypars mspec.FormalReturnType retInfo let methName = mspec.Name let tref = mspec.MethodRef.DeclaringTypeRef - let EmitTheMethodDef (mdef: ILMethodDef) = - // Does the function have an explicit [] attribute? - let isExplicitEntryPoint = HasFSharpAttribute g g.attrib_EntryPointAttribute attrs - - let mdef = - mdef - .WithSecurity(not (List.isEmpty securityAttributes)) - .WithPInvoke(hasDllImport) - .WithPreserveSig(hasPreserveSigImplFlag || hasPreserveSigNamedArg) - .WithSynchronized(hasSynchronizedImplFlag) - .WithNoInlining(hasNoInliningFlag) - .WithAggressiveInlining(hasAggressiveInliningImplFlag) - .With(isEntryPoint=isExplicitEntryPoint, securityDecls=secDecls) - - let mdef = - if // operator names - mdef.Name.StartsWithOrdinal("op_") || - // active pattern names - mdef.Name.StartsWithOrdinal("|") || - // event add/remove method - v.val_flags.IsGeneratedEventVal then - mdef.WithSpecialName - else - mdef - CountMethodDef() - cgbuf.mgbuf.AddMethodDef(tref, mdef) - - match v.MemberInfo with // don't generate unimplemented abstracts | Some memberInfo when memberInfo.MemberFlags.IsDispatchSlot && not memberInfo.IsImplemented -> // skipping unimplemented abstract method () - | Some memberInfo when not v.IsExtensionMember -> - - let ilMethTypars = ilTypars |> List.drop mspec.DeclaringType.GenericArgs.Length - if memberInfo.MemberFlags.MemberKind = MemberKind.Constructor then - assert (isNil ilMethTypars) - let mdef = mkILCtor (access, ilParams, ilMethodBody) - let mdef = mdef.With(customAttrs= mkILCustomAttrs (ilAttrsThatGoOnPrimaryItem @ sourceNameAttribs @ ilAttrsCompilerGenerated)) - EmitTheMethodDef mdef - - elif memberInfo.MemberFlags.MemberKind = MemberKind.ClassConstructor then - assert (isNil ilMethTypars) - let mdef = mkILClassCtor ilMethodBody - let mdef = mdef.With(customAttrs= mkILCustomAttrs (ilAttrsThatGoOnPrimaryItem @ sourceNameAttribs @ ilAttrsCompilerGenerated)) - EmitTheMethodDef mdef - - // Generate virtual/override methods + method-impl information if needed - else - let mdef = - if not compileAsInstance then - mkILStaticMethod (ilMethTypars, v.CompiledName, access, ilParams, ilReturn, ilMethodBody) - elif (memberInfo.MemberFlags.IsDispatchSlot && memberInfo.IsImplemented) || - memberInfo.MemberFlags.IsOverrideOrExplicitImpl then + // compiling CLIEvent properties + | Some memberInfo + when not v.IsExtensionMember && + (match memberInfo.MemberFlags.MemberKind with + | (MemberKind.PropertySet | MemberKind.PropertyGet) -> CompileAsEvent cenv.g v.Attribs + | _ -> false) -> - let flagFixups = ComputeFlagFixupsForMemberBinding cenv (v, memberInfo) - let mdef = mkILGenericVirtualMethod (v.CompiledName, ILMemberAccess.Public, ilMethTypars, ilParams, ilReturn, ilMethodBody) - let mdef = List.fold (fun mdef f -> f mdef) mdef flagFixups + let useMethodImpl = + if compileAsInstance && + ((memberInfo.MemberFlags.IsDispatchSlot && memberInfo.IsImplemented) || + memberInfo.MemberFlags.IsOverrideOrExplicitImpl) then - // fixup can potentially change name of reflected definition that was already recorded - patch it if necessary - cgbuf.mgbuf.ReplaceNameOfReflectedDefinition(v, mdef.Name) - mdef - else - mkILGenericNonVirtualMethod (v.CompiledName, access, ilMethTypars, ilParams, ilReturn, ilMethodBody) + let useMethodImpl = memberInfo.ImplementedSlotSigs |> List.exists (fun slotsig -> ComputeUseMethodImpl cenv (v, slotsig)) + + let nameOfOverridingMethod = + match ComputeMethodImplNameFixupForMemberBinding cenv (v, memberInfo) with + | None -> mspec.Name + | Some nm -> nm + + // Fixup can potentially change name of reflected definition that was already recorded - patch it if necessary + cgbuf.mgbuf.ReplaceNameOfReflectedDefinition(v, nameOfOverridingMethod) + useMethodImpl + else + false - let isAbstract = - memberInfo.MemberFlags.IsDispatchSlot && - let tcref = v.MemberApparentEntity - not tcref.Deref.IsFSharpDelegateTycon + // skip method generation for compiling the property as a .NET event + // Instead emit the pseudo-property as an event. + // on't do this if it's a private method impl. + if not useMethodImpl then + let edef = GenEventForProperty cenv eenvForMeth mspec v ilAttrsThatGoOnPrimaryItem m returnTy + cgbuf.mgbuf.AddEventDef(tref, edef) - let mdef = - if mdef.IsVirtual then - mdef.WithFinal(memberInfo.MemberFlags.IsFinal).WithAbstract(isAbstract) - else mdef + | _ -> + + let mdef = + match v.MemberInfo with + | Some(memberInfo) when not v.IsExtensionMember -> + + let ilMethTypars = ilTypars |> List.drop mspec.DeclaringType.GenericArgs.Length + if memberInfo.MemberFlags.MemberKind = MemberKind.Constructor then + assert (isNil ilMethTypars) + let mdef = mkILCtor (access, ilParams, ilMethodBody) + let mdef = mdef.With(customAttrs= mkILCustomAttrs (ilAttrsThatGoOnPrimaryItem @ sourceNameAttribs @ ilAttrsCompilerGenerated)) + mdef + + elif memberInfo.MemberFlags.MemberKind = MemberKind.ClassConstructor then + assert (isNil ilMethTypars) + let mdef = mkILClassCtor ilMethodBody + let mdef = mdef.With(customAttrs= mkILCustomAttrs (ilAttrsThatGoOnPrimaryItem @ sourceNameAttribs @ ilAttrsCompilerGenerated)) + mdef + + // Generate virtual/override methods + method-impl information if needed + else + let mdef = + if not compileAsInstance then + mkILStaticMethod (ilMethTypars, mspec.Name, access, ilParams, ilReturn, ilMethodBody) + + elif (memberInfo.MemberFlags.IsDispatchSlot && memberInfo.IsImplemented) || + memberInfo.MemberFlags.IsOverrideOrExplicitImpl then - match memberInfo.MemberFlags.MemberKind with + let flagFixups = ComputeFlagFixupsForMemberBinding cenv (v, memberInfo) + let mdef = mkILGenericVirtualMethod (mspec.Name, ILMemberAccess.Public, ilMethTypars, ilParams, ilReturn, ilMethodBody) + let mdef = List.fold (fun mdef f -> f mdef) mdef flagFixups + + // fixup can potentially change name of reflected definition that was already recorded - patch it if necessary + cgbuf.mgbuf.ReplaceNameOfReflectedDefinition(v, mdef.Name) + mdef + else + mkILGenericNonVirtualMethod (mspec.Name, access, ilMethTypars, ilParams, ilReturn, ilMethodBody) + + let isAbstract = + memberInfo.MemberFlags.IsDispatchSlot && + let tcref = v.MemberApparentEntity + not tcref.Deref.IsFSharpDelegateTycon + + let mdef = + if mdef.IsVirtual then + mdef.WithFinal(memberInfo.MemberFlags.IsFinal).WithAbstract(isAbstract) + else mdef + + match memberInfo.MemberFlags.MemberKind with - | (MemberKind.PropertySet | MemberKind.PropertyGet) -> - if not (isNil ilMethTypars) then - error(InternalError("A property may not be more generic than the enclosing type - constrain the polymorphism in the expression", v.Range)) + | (MemberKind.PropertySet | MemberKind.PropertyGet) -> + if not (isNil ilMethTypars) then + error(InternalError("A property may not be more generic than the enclosing type - constrain the polymorphism in the expression", v.Range)) - // Check if we're compiling the property as a .NET event - if CompileAsEvent g v.Attribs then + // Check if we're compiling the property as a .NET event + assert not (CompileAsEvent cenv.g v.Attribs) - // Emit the pseudo-property as an event, but not if its a private method impl - if mdef.Access <> ILMemberAccess.Private then - let edef = GenEventForProperty cenv eenvForMeth mspec v ilAttrsThatGoOnPrimaryItem m returnTy - cgbuf.mgbuf.AddEventDef(tref, edef) - // The method def is dropped on the floor here - - else // Emit the property, but not if its a private method impl if mdef.Access <> ILMemberAccess.Private then let vtyp = ReturnTypeOfPropertyVal g v @@ -5836,26 +6079,53 @@ and GenMethodForBinding // Add the special name flag for all properties let mdef = mdef.WithSpecialName.With(customAttrs= mkILCustomAttrs ((GenAttrs cenv eenv attrsAppliedToGetterOrSetter) @ sourceNameAttribs @ ilAttrsCompilerGenerated)) - EmitTheMethodDef mdef - | _ -> - let mdef = mdef.With(customAttrs= mkILCustomAttrs (ilAttrsThatGoOnPrimaryItem @ sourceNameAttribs @ ilAttrsCompilerGenerated)) - EmitTheMethodDef mdef + mdef + | _ -> + let mdef = mdef.With(customAttrs= mkILCustomAttrs (ilAttrsThatGoOnPrimaryItem @ sourceNameAttribs @ ilAttrsCompilerGenerated)) + mdef - | _ -> - let mdef = mkILStaticMethod (ilTypars, methName, access, ilParams, ilReturn, ilMethodBody) + | _ -> + let mdef = mkILStaticMethod (ilTypars, methName, access, ilParams, ilReturn, ilMethodBody) + + // For extension properties, also emit attrsAppliedToGetterOrSetter on the getter or setter method + let ilAttrs = + match v.MemberInfo with + | Some memberInfo when v.IsExtensionMember -> + match memberInfo.MemberFlags.MemberKind with + | (MemberKind.PropertySet | MemberKind.PropertyGet) -> ilAttrsThatGoOnPrimaryItem @ GenAttrs cenv eenv attrsAppliedToGetterOrSetter + | _ -> ilAttrsThatGoOnPrimaryItem + | _ -> ilAttrsThatGoOnPrimaryItem + + let ilCustomAttrs = mkILCustomAttrs (ilAttrs @ sourceNameAttribs @ ilAttrsCompilerGenerated) + let mdef = mdef.With(customAttrs= ilCustomAttrs) + mdef - // For extension properties, also emit attrsAppliedToGetterOrSetter on the getter or setter method - let ilAttrs = - match v.MemberInfo with - | Some memberInfo when v.IsExtensionMember -> - match memberInfo.MemberFlags.MemberKind with - | (MemberKind.PropertySet | MemberKind.PropertyGet) -> ilAttrsThatGoOnPrimaryItem @ GenAttrs cenv eenv attrsAppliedToGetterOrSetter - | _ -> ilAttrsThatGoOnPrimaryItem - | _ -> ilAttrsThatGoOnPrimaryItem - - let ilCustomAttrs = mkILCustomAttrs (ilAttrs @ sourceNameAttribs @ ilAttrsCompilerGenerated) - let mdef = mdef.With(customAttrs= ilCustomAttrs) - EmitTheMethodDef mdef + // Does the function have an explicit [] attribute? + let isExplicitEntryPoint = HasFSharpAttribute cenv.g cenv.g.attrib_EntryPointAttribute attrs + + let mdef = + mdef + .WithSecurity(not (List.isEmpty securityAttributes)) + .WithPInvoke(hasDllImport) + .WithPreserveSig(hasPreserveSigImplFlag || hasPreserveSigNamedArg) + .WithSynchronized(hasSynchronizedImplFlag) + .WithNoInlining(hasNoInliningFlag) + .WithAggressiveInlining(hasAggressiveInliningImplFlag) + .With(isEntryPoint=isExplicitEntryPoint, securityDecls=secDecls) + + let mdef = + if // operator names + mdef.Name.StartsWithOrdinal("op_") || + // active pattern names + mdef.Name.StartsWithOrdinal("|") || + // event add/remove method + v.val_flags.IsGeneratedEventVal then + mdef.WithSpecialName + else + mdef + CountMethodDef() + cgbuf.mgbuf.AddMethodDef(tref, mdef) + and GenPInvokeMethod (nm, dll, namedArgs) = let decoder = AttributeDecoder namedArgs @@ -5894,7 +6164,7 @@ and GenBindings cenv cgbuf eenv binds = List.iter (GenBinding cenv cgbuf eenv) b and GenSetVal cenv cgbuf eenv (vref, e, m) sequel = let storage = StorageForValRef m vref eenv match storage with - | Env (ilCloTy, _, _, _) -> + | Env (ilCloTy, _, _) -> CG.EmitInstr cgbuf (pop 0) (Push [ilCloTy]) mkLdarg0 | _ -> () @@ -5963,7 +6233,7 @@ and GenSetStorage m cgbuf storage = | StaticProperty (ilGetterMethSpec, _) -> error(Error(FSComp.SR.ilStaticMethodIsNotLambda(ilGetterMethSpec.Name), m)) - | Method (_, _, mspec, m, _, _, _) -> + | Method (_, _, mspec, _, m, _, _, _, _, _, _, _) -> error(Error(FSComp.SR.ilStaticMethodIsNotLambda(mspec.Name), m)) | Null -> @@ -5972,28 +6242,33 @@ and GenSetStorage m cgbuf storage = | Arg _ -> error(Error(FSComp.SR.ilMutableVariablesCannotEscapeMethod(), m)) - | Env (_, _, ilField, _) -> + | Env (_, ilField, _) -> // Note: ldarg0 has already been emitted in GenSetVal CG.EmitInstr cgbuf (pop 2) Push0 (mkNormalStfld ilField) -and CommitGetStorageSequel cenv cgbuf eenv m ty localCloInfo storeSequel = - match localCloInfo, storeSequel with - | Some {contents =NamedLocalIlxClosureInfoGenerator _cloinfo}, _ -> error(InternalError("Unexpected generator", m)) +and CommitGetStorageSequel cenv cgbuf eenv m ty localCloInfo fetchSequel = + match localCloInfo, fetchSequel with + | Some {contents =NamedLocalIlxClosureInfoGenerator _cloinfo}, _ -> + error(InternalError("Unexpected generator", m)) + | Some {contents =NamedLocalIlxClosureInfoGenerated cloinfo}, Some (tyargs, args, m, sequel) when not (isNil tyargs) -> let actualRetTy = GenNamedLocalTyFuncCall cenv cgbuf eenv ty cloinfo tyargs m CommitGetStorageSequel cenv cgbuf eenv m actualRetTy None (Some ([], args, m, sequel)) + | _, None -> () + | _, Some ([], [], _, sequel) -> GenSequel cenv eenv.cloc cgbuf sequel + | _, Some (tyargs, args, m, sequel) -> - GenArgsAndIndirectCall cenv cgbuf eenv (ty, tyargs, args, m) sequel + GenCurriedArgsAndIndirectCall cenv cgbuf eenv (ty, tyargs, args, m) sequel -and GenGetStorageAndSequel cenv cgbuf eenv m (ty, ilTy) storage storeSequel = +and GenGetStorageAndSequel (cenv: cenv) cgbuf eenv m (ty, ilTy) storage fetchSequel = let g = cenv.g match storage with | Local (idx, _, localCloInfo) -> EmitGetLocal cgbuf ilTy idx - CommitGetStorageSequel cenv cgbuf eenv m ty localCloInfo storeSequel + CommitGetStorageSequel cenv cgbuf eenv m ty localCloInfo fetchSequel | StaticField (fspec, _, hasLiteralAttr, ilContainerTy, _, _, ilGetterMethRef, _, _) -> // References to literals go directly to the field - no property is used @@ -6001,13 +6276,13 @@ and GenGetStorageAndSequel cenv cgbuf eenv m (ty, ilTy) storage storeSequel = EmitGetStaticField cgbuf ilTy fspec else CG.EmitInstr cgbuf (pop 0) (Push [ilTy]) (I_call(Normalcall, mkILMethSpecForMethRefInTy (ilGetterMethRef, ilContainerTy, []), None)) - CommitGetStorageSequel cenv cgbuf eenv m ty None storeSequel + CommitGetStorageSequel cenv cgbuf eenv m ty None fetchSequel | StaticProperty (ilGetterMethSpec, _) -> CG.EmitInstr cgbuf (pop 0) (Push [ilTy]) (I_call (Normalcall, ilGetterMethSpec, None)) - CommitGetStorageSequel cenv cgbuf eenv m ty None storeSequel + CommitGetStorageSequel cenv cgbuf eenv m ty None fetchSequel - | Method (topValInfo, vref, mspec, _, _, _, _) -> + | Method (topValInfo, vref, _, _, _, _, _, _, _, _, _, _) -> // Get a toplevel value as a first-class value. // We generate a lambda expression and that simply calls // the toplevel method. However we optimize the case where we are @@ -6018,27 +6293,27 @@ and GenGetStorageAndSequel cenv cgbuf eenv m (ty, ilTy) storage storeSequel = let expr, exprty = AdjustValForExpectedArity g m vref NormalValUse topValInfo // Then reduce out any arguments (i.e. apply the sequel immediately if we can...) - match storeSequel with + match fetchSequel with | None -> GenLambda cenv cgbuf eenv false None expr Continue | Some (tyargs', args, m, sequel) -> let specializedExpr = - if isNil args && isNil tyargs' then failwith ("non-lambda at use of method " + mspec.Name) - MakeApplicationAndBetaReduce g (expr, exprty, [tyargs'], args, m) + if isNil args && isNil tyargs' then failwith ("non-lambda at use of method " + vref.CompiledName) + MakeApplicationAndBetaReduce cenv.g (expr, exprty, [tyargs'], args, m) GenExpr cenv cgbuf eenv SPSuppress specializedExpr sequel | Null -> CG.EmitInstr cgbuf (pop 0) (Push [ilTy]) (AI_ldnull) - CommitGetStorageSequel cenv cgbuf eenv m ty None storeSequel + CommitGetStorageSequel cenv cgbuf eenv m ty None fetchSequel | Arg i -> CG.EmitInstr cgbuf (pop 0) (Push [ilTy]) (mkLdarg (uint16 i)) - CommitGetStorageSequel cenv cgbuf eenv m ty None storeSequel + CommitGetStorageSequel cenv cgbuf eenv m ty None fetchSequel - | Env (_, _, ilField, localCloInfo) -> + | Env (_, ilField, localCloInfo) -> // Note: ldarg 0 is emitted in 'cu_erase' erasure of the ldenv instruction CG.EmitInstrs cgbuf (pop 0) (Push [ilTy]) [ mkLdarg0; mkNormalLdfld ilField ] - CommitGetStorageSequel cenv cgbuf eenv m ty localCloInfo storeSequel + CommitGetStorageSequel cenv cgbuf eenv m ty localCloInfo fetchSequel and GenGetLocalVals cenv cgbuf eenvouter m fvs = List.iter (fun v -> GenGetLocalVal cenv cgbuf eenvouter m v None) fvs @@ -6104,7 +6379,7 @@ and AllocStorageForBinds cenv cgbuf scopeMarks eenv binds = | Some repr -> match repr with | Local(_, _, Some g) - | Env(_, _, _, Some g) -> + | Env(_, _, Some g) -> match !g with | NamedLocalIlxClosureInfoGenerator f -> g := NamedLocalIlxClosureInfoGenerated (f eenv) | NamedLocalIlxClosureInfoGenerated _ -> () @@ -6264,7 +6539,7 @@ and GenAttr amap g eenv (Attrib(_, k, args, props, _, _, _)) = | ILAttrib mref -> mkILMethSpec(mref, AsObject, [], []) | FSAttrib vref -> assert(vref.IsMember) - let mspec, _, _, _, _, _ = GetMethodSpecForMemberVal amap g (Option.get vref.MemberInfo) vref + let mspec, _, _, _, _, _, _, _, _ = GetMethodSpecForMemberVal amap g (Option.get vref.MemberInfo) vref mspec let ilArgs = List.map2 (fun (AttribExpr(_, vexpr)) ty -> GenAttribArg amap g eenv vexpr ty) args mspec.FormalArgTypes mkILCustomAttribMethRef g.ilg (mspec, ilArgs, props) @@ -6591,6 +6866,24 @@ and GenFieldInit m c = | ConstToILFieldInit fieldInit -> fieldInit | _ -> error(Error(FSComp.SR.ilTypeCannotBeUsedForLiteralField(), m)) +and GenWitnessParams cenv eenv m (witnessInfos: TraitWitnessInfos) = + ((Set.empty, 0), witnessInfos) ||> List.mapFold (fun (used,i) witnessInfo -> + let ty = GenWitnessTy cenv.g witnessInfo + let nm = String.uncapitalize witnessInfo.MemberName + let nm = if used.Contains nm then nm + string i else nm + let ilParam = + { Name=Some nm + Type= GenType cenv.amap m eenv.tyenv ty + Default=None + Marshal=None + IsIn=false + IsOut=false + IsOptional=false + CustomAttrsStored = storeILCustomAttrs (mkILCustomAttrs []) + MetadataIndex = NoMetadataIdx }: ILParameter + ilParam, (used.Add nm, i + 1)) + |> fst + and GenAbstractBinding cenv eenv tref (vref: ValRef) = assert(vref.IsMember) let g = cenv.g @@ -6603,11 +6896,15 @@ and GenAbstractBinding cenv eenv tref (vref: ValRef) = [ yield! GenAttrs cenv eenv attribs yield! GenCompilationArgumentCountsAttr cenv vref.Deref ] - let mspec, ctps, mtps, argInfos, retInfo, methodArgTys = GetMethodSpecForMemberVal cenv.amap g memberInfo vref + let mspec, _mspecW, ctps, mtps, _curriedArgInfos, argInfos, retInfo, witnessInfos, methArgTys = + GetMethodSpecForMemberVal cenv.amap cenv.g memberInfo vref + + assert witnessInfos.IsEmpty + let eenvForMeth = EnvForTypars (ctps@mtps) eenv let ilMethTypars = GenGenericParams cenv eenvForMeth mtps let ilReturn = GenReturnInfo cenv eenvForMeth mspec.FormalReturnType retInfo - let ilParams = GenParams cenv eenvForMeth mspec argInfos methodArgTys None + let ilParams = GenParams cenv eenvForMeth m mspec [] argInfos methArgTys None let compileAsInstance = ValRefIsCompiledAsInstanceMember g vref let mdef = mkILGenericVirtualMethod (vref.CompiledName, ILMemberAccess.Public, ilMethTypars, ilParams, ilReturn, MethodBody.Abstract) @@ -6651,9 +6948,9 @@ and GenAbstractBinding cenv eenv tref (vref: ValRef) = /// Generate a ToString method that calls 'sprintf "%A"' and GenToStringMethod cenv eenv ilThisTy m = let g = cenv.g - [ match (eenv.valsInScope.TryFind g.sprintf_vref.Deref, - eenv.valsInScope.TryFind g.new_format_vref.Deref) with - | Some(Lazy(Method(_, _, sprintfMethSpec, _, _, _, _))), Some(Lazy(Method(_, _, newFormatMethSpec, _, _, _, _))) -> + [ match (eenv.valsInScope.TryFind cenv.g.sprintf_vref.Deref, + eenv.valsInScope.TryFind cenv.g.new_format_vref.Deref) with + | Some(Lazy(Method(_, _, sprintfMethSpec, _, _, _, _, _, _, _, _, _))), Some(Lazy(Method(_, _, newFormatMethSpec, _, _, _, _, _, _, _, _, _))) -> // The type returned by the 'sprintf' call let funcTy = EraseClosures.mkILFuncTy g.ilxPubCloEnv ilThisTy g.ilg.typ_String // Give the instantiation of the printf format object, i.e. a Format`5 object compatible with StringFormat @@ -6981,9 +7278,9 @@ and GenTypeDef cenv mgbuf lazyInitInfo eenv m (tycon: Tycon) = if generateDebugDisplayAttribute then let (|Lazy|) (x: Lazy<_>) = x.Force() - match (eenv.valsInScope.TryFind g.sprintf_vref.Deref, - eenv.valsInScope.TryFind g.new_format_vref.Deref) with - | Some(Lazy(Method(_, _, sprintfMethSpec, _, _, _, _))), Some(Lazy(Method(_, _, newFormatMethSpec, _, _, _, _))) -> + match (eenv.valsInScope.TryFind cenv.g.sprintf_vref.Deref, + eenv.valsInScope.TryFind cenv.g.new_format_vref.Deref) with + | Some(Lazy(Method(_, _, sprintfMethSpec, _, _, _, _, _, _, _, _, _))), Some(Lazy(Method(_, _, newFormatMethSpec, _, _, _, _, _, _, _, _, _))) -> // The type returned by the 'sprintf' call let funcTy = EraseClosures.mkILFuncTy g.ilxPubCloEnv ilThisTy g.ilg.typ_String // Give the instantiation of the printf format object, i.e. a Format`5 object compatible with StringFormat @@ -7428,12 +7725,18 @@ let CodegenAssembly cenv eenv mgbuf fileImpls = // structures representing the contents of the module. //------------------------------------------------------------------------- -let GetEmptyIlxGenEnv (ilg: ILGlobals) ccu = +let GetEmptyIlxGenEnv (g: TcGlobals) ccu = let thisCompLoc = CompLocForCcu ccu { tyenv=TypeReprEnv.Empty cloc = thisCompLoc valsInScope=ValMap<_>.Empty - someTypeInThisAssembly=ilg.typ_Object (* dummy value *) + witnessesInScope= + ImmutableDictionary.Create( + { new IEqualityComparer<_> with + member __.Equals(a, b) = traitKeysAEquiv g TypeEquivEnv.Empty a b + member __.GetHashCode(a) = hash a.MemberName + }) + someTypeInThisAssembly= g.ilg.typ_Object // dummy value isFinalFile = false letBoundVars=[] liveLocals=IntMap.empty() @@ -7475,7 +7778,8 @@ let GenerateCode (cenv, anonTypeTable, eenv, TypedAssemblyAfterOptimization file match reflectedDefinitions with | [] -> [] | _ -> - let qscope = QuotationTranslator.QuotationGenerationScope.Create (g, cenv.amap, cenv.viewCcu, QuotationTranslator.IsReflectedDefinition.Yes) + // TODO: generate witness parameters for reflected definitions + let qscope = QuotationTranslator.QuotationGenerationScope.Create (cenv.g, cenv.amap, cenv.viewCcu, cenv.tcVal, QuotationTranslator.IsReflectedDefinition.Yes) let defns = reflectedDefinitions |> List.choose (fun ((methName, v), e) -> try @@ -7620,7 +7924,7 @@ let ClearGeneratedValue (ctxt: ExecutionContext) (_g: TcGlobals) eenv (v: Val) = type IlxAssemblyGenerator(amap: ImportMap, tcGlobals: TcGlobals, tcVal: ConstraintSolver.TcValF, ccu: Tast.CcuThunk) = // The incremental state held by the ILX code generator - let mutable ilxGenEnv = GetEmptyIlxGenEnv tcGlobals.ilg ccu + let mutable ilxGenEnv = GetEmptyIlxGenEnv tcGlobals ccu let anonTypeTable = AnonTypeGenerationTable() let intraAssemblyInfo = { StaticFieldInfo = new Dictionary<_, _>(HashIdentity.Structural) } let casApplied = new Dictionary() @@ -7638,7 +7942,7 @@ type IlxAssemblyGenerator(amap: ImportMap, tcGlobals: TcGlobals, tcVal: Constrai member __.GenerateCode (codeGenOpts, typedAssembly, assemAttribs, moduleAttribs) = let cenv: cenv = { g=tcGlobals - TcVal = tcVal + tcVal = tcVal viewCcu = ccu ilUnitTy = None amap = amap diff --git a/src/fsharp/MethodCalls.fs b/src/fsharp/MethodCalls.fs index 2f8fd8bbbc3..60c0465edb1 100644 --- a/src/fsharp/MethodCalls.fs +++ b/src/fsharp/MethodCalls.fs @@ -1327,3 +1327,125 @@ exception FieldNotMutable of DisplayEnv * Tast.RecdFieldRef * range let CheckRecdFieldMutation m denv (rfinfo: RecdFieldInfo) = if not rfinfo.RecdField.IsMutable then error (FieldNotMutable(denv, rfinfo.RecdFieldRef, m)) + +let GenWitnessExpr amap g m (traitInfo: TraitConstraintInfo) argExprs = + + let sln = + match traitInfo.Solution with + | None -> Choice5Of5() + | Some sln -> + match sln with + | ILMethSln(origTy, extOpt, mref, minst) -> + let metadataTy = convertToTypeWithMetadataIfPossible g origTy + let tcref = tcrefOfAppTy g metadataTy + let mdef = resolveILMethodRef tcref.ILTyconRawMetadata mref + let ilMethInfo = + match extOpt with + | None -> MethInfo.CreateILMeth(amap, m, origTy, mdef) + | Some ilActualTypeRef -> + let actualTyconRef = Import.ImportILTypeRef amap m ilActualTypeRef + MethInfo.CreateILExtensionMeth(amap, m, origTy, actualTyconRef, None, mdef) + Choice1Of5 (ilMethInfo, minst) + | FSMethSln(ty, vref, minst) -> + Choice1Of5 (FSMeth(g, ty, vref, None), minst) + | FSRecdFieldSln(tinst, rfref, isSetProp) -> + Choice2Of5 (tinst, rfref, isSetProp) + | FSAnonRecdFieldSln(anonInfo, tinst, i) -> + Choice3Of5 (anonInfo, tinst, i) + | BuiltInSln -> + Choice5Of5 () + | ClosedExprSln expr -> + Choice4Of5 expr + + match sln with + | Choice1Of5(minfo, methArgTys) -> + let argExprs = + // FIX for #421894 - typechecker assumes that coercion can be applied for the trait calls arguments but codegen doesn't emit coercion operations + // result - generation of non-verifyable code + // fix - apply coercion for the arguments (excluding 'receiver' argument in instance calls) + + // flatten list of argument types (looks like trait calls with curried arguments are not supported so we can just convert argument list in straighforward way) + let argTypes = + minfo.GetParamTypes(amap, m, methArgTys) + |> List.concat + // do not apply coercion to the 'receiver' argument + let receiverArgOpt, argExprs = + if minfo.IsInstance then + match argExprs with + | h::t -> Some h, t + | argExprs -> None, argExprs + else None, argExprs + let convertedArgs = (argExprs, argTypes) ||> List.map2 (fun expr expectedTy -> mkCoerceIfNeeded g expectedTy (tyOfExpr g expr) expr) + match receiverArgOpt with + | Some r -> r::convertedArgs + | None -> convertedArgs + + // Fix bug 1281: If we resolve to an instance method on a struct and we haven't yet taken + // the address of the object then go do that + if minfo.IsStruct && minfo.IsInstance && (match argExprs with [] -> false | h :: _ -> not (isByrefTy g (tyOfExpr g h))) then + let h, t = List.headAndTail argExprs + let wrap, h', _readonly, _writeonly = mkExprAddrOfExpr g true false PossiblyMutates h None m + Some (wrap (Expr.Op(TOp.TraitCall(traitInfo), [], (h' :: t), m))) + else + Some (MakeMethInfoCall amap m minfo methArgTys argExprs ) + + | Choice2Of5 (tinst, rfref, isSet) -> + match isSet, rfref.RecdField.IsStatic, argExprs.Length with + | true, true, 1 -> + Some (mkStaticRecdFieldSet (rfref, tinst, argExprs.[0], m)) + | true, false, 2 -> + // If we resolve to an instance field on a struct and we haven't yet taken + // the address of the object then go do that + if rfref.Tycon.IsStructOrEnumTycon && not (isByrefTy g (tyOfExpr g argExprs.[0])) then + let h = List.head argExprs + let wrap, h', _readonly, _writeonly = mkExprAddrOfExpr g true false DefinitelyMutates h None m + Some (wrap (mkRecdFieldSetViaExprAddr (h', rfref, tinst, argExprs.[1], m))) + else + Some (mkRecdFieldSetViaExprAddr (argExprs.[0], rfref, tinst, argExprs.[1], m)) + | false, true, 0 -> + Some (mkStaticRecdFieldGet (rfref, tinst, m)) + | false, false, 1 -> + if rfref.Tycon.IsStructOrEnumTycon && isByrefTy g (tyOfExpr g argExprs.[0]) then + Some (mkRecdFieldGetViaExprAddr (argExprs.[0], rfref, tinst, m)) + else + Some (mkRecdFieldGet g (argExprs.[0], rfref, tinst, m)) + | _ -> None + + | Choice3Of5 (anonInfo, tinst, i) -> + let tupInfo = anonInfo.TupInfo + if evalTupInfoIsStruct tupInfo && isByrefTy g (tyOfExpr g argExprs.[0]) then + Some (mkAnonRecdFieldGetViaExprAddr (anonInfo, argExprs.[0], tinst, i, m)) + else + Some (mkAnonRecdFieldGet g (anonInfo, argExprs.[0], tinst, i, m)) + + | Choice4Of5 expr -> + Some (MakeApplicationAndBetaReduce g (expr, tyOfExpr g expr, [], argExprs, m)) + + | Choice5Of5 () -> + match traitInfo.Solution with + | None -> None // the trait has been generalized + | Some _-> + // For these operators, the witness is just a call to the coresponding FSharp.Core operator + match g.tryMakeOperatorAsBuiltInWitnessInfo isStringTy isArrayTy traitInfo argExprs with + | Some (info, tyargs, actualArgExprs) -> + tryMkCallCoreFunctionAsBuiltInWitness g info tyargs actualArgExprs m + | None -> + // For all other built-in operators, the witness is a call to the coresponding BuiltInWitnesses operator + // These are called as F# methods not F# functions + tryMkCallBuiltInWitness g traitInfo argExprs m + +let GenWitnessExprLambda amap g m (traitInfo: TraitConstraintInfo) = + let witnessInfo = traitInfo.TraitKey + let argtysl = GenWitnessArgTys g witnessInfo + let vse = argtysl |> List.mapiSquared (fun i j ty -> mkCompGenLocal m ("arg" + string i + "_" + string j) ty) + let vsl = List.mapSquared fst vse + match GenWitnessExpr amap g m traitInfo (List.concat (List.mapSquared snd vse)) with + | Some expr -> + Choice2Of2 (mkMemberLambdas m [] None None vsl (expr, tyOfExpr g expr)) + | None -> + Choice1Of2 witnessInfo + //assert ("A constraint witness could not be found for a built-in constraint solution" |> ignore; false) + //mkOne g m + +let GenNonGenericWitnessArgs amap g m (traitInfos: TraitConstraintInfo list) = + [ for traitInfo in traitInfos -> GenWitnessExprLambda amap g m traitInfo ] diff --git a/src/fsharp/MethodOverrides.fs b/src/fsharp/MethodOverrides.fs index c621706b9b8..a3321bffa97 100644 --- a/src/fsharp/MethodOverrides.fs +++ b/src/fsharp/MethodOverrides.fs @@ -87,7 +87,8 @@ module DispatchSlotChecking = /// Get the override info for a value being used to implement a dispatch slot. let GetTypeMemberOverrideInfo g reqdTy (overrideBy: ValRef) = - let _, argInfos, retTy, _ = GetTypeOfMemberInMemberForm g overrideBy + // TODO: consider witnesses w.r.t. overriding methods as types get more specialized.... + let _, _cxs, argInfos, retTy, _ = GetTypeOfMemberInMemberForm g overrideBy let nm = overrideBy.LogicalName let argTys = argInfos |> List.mapSquared fst @@ -126,7 +127,7 @@ module DispatchSlotChecking = /// Get the override information for an object expression method being used to implement dispatch slots let GetObjectExprOverrideInfo g amap (implty, id: Ident, memberFlags, ty, arityInfo, bindingAttribs, rhsExpr) = // Dissect the type - let tps, argInfos, retTy, _ = GetMemberTypeInMemberForm g memberFlags arityInfo ty id.idRange + let tps, _cxs, argInfos, retTy, _ = GetMemberTypeInMemberForm g memberFlags arityInfo ty id.idRange let argTys = argInfos |> List.mapSquared fst // Dissect the implementation let _, ctorThisValOpt, baseValOpt, vsl, rhsExpr, _ = destTopLambda g amap arityInfo (rhsExpr, ty) diff --git a/src/fsharp/NicePrint.fs b/src/fsharp/NicePrint.fs index ab45f12c137..1ee6622c337 100644 --- a/src/fsharp/NicePrint.fs +++ b/src/fsharp/NicePrint.fs @@ -668,7 +668,7 @@ module private PrintTypes = PrintIL.layoutILTypeRef denv tref ++ argsL | FSAttrib vref -> // REVIEW: this is not trimming "Attribute" - let _, _, rty, _ = GetTypeOfMemberInMemberForm denv.g vref + let _, _cxs, _, rty, _ = GetTypeOfMemberInMemberForm denv.g vref let rty = GetFSharpViewOfReturnType denv.g rty let tcref = tcrefOfAppTy denv.g rty layoutTyconRef denv tcref ++ argsL @@ -716,7 +716,7 @@ module private PrintTypes = PrintIL.layoutILType denv [] ty ++ argsL /// Layout '[]' above another block - and layoutAttribs denv ty kind attrs restL = + and layoutAttribs denv isValue ty kind attrs restL = if denv.showAttributes then // Don't display DllImport attributes in generated signatures @@ -734,8 +734,9 @@ module private PrintTypes = | _ -> squareAngleL (sepListL (rightL (tagPunctuation ";")) (List.map (layoutAttrib denv) attrs)) @@ restL - elif Tastops.isStructRecordOrUnionTyconTy denv.g ty || - ((Tastops.isUnionTy denv.g ty || Tastops.isRecdTy denv.g ty) && HasFSharpAttribute denv.g denv.g.attrib_StructAttribute attrs) then + elif not isValue && + (Tastops.isStructRecordOrUnionTyconTy denv.g ty + || ((Tastops.isUnionTy denv.g ty || Tastops.isRecdTy denv.g ty) && HasFSharpAttribute denv.g denv.g.attrib_StructAttribute attrs)) then squareAngleL (wordL (tagClass "Struct")) @@ restL else match kind with @@ -1231,7 +1232,7 @@ module private PrintTastMemberOrVals = prettyTyparInst, resL | Some _ -> prettyLayoutOfMember denv typarInst v - prettyTyparInst, layoutAttribs denv v.Type TyparKind.Type v.Attribs vL + prettyTyparInst, layoutAttribs denv true v.Type TyparKind.Type v.Attribs vL let prettyLayoutOfValOrMemberNoInst denv v = prettyLayoutOfValOrMember denv emptyTyparInst v |> snd @@ -1807,7 +1808,7 @@ module private TastDefinitionPrinting = addMembersAsWithEnd (lhsL ^^ WordL.equals) | Some a -> (lhsL ^^ WordL.equals) --- (layoutType { denv with shortTypeNames = false } a) - layoutAttribs denv ty tycon.TypeOrMeasureKind tycon.Attribs reprL + layoutAttribs denv false ty tycon.TypeOrMeasureKind tycon.Attribs reprL // Layout: exception definition let layoutExnDefn denv (exnc: Entity) = diff --git a/src/fsharp/Optimizer.fs b/src/fsharp/Optimizer.fs index b94cedf9625..4a73c01cd38 100644 --- a/src/fsharp/Optimizer.fs +++ b/src/fsharp/Optimizer.fs @@ -136,16 +136,33 @@ type ValInfos(entries) = t.Add (vref.Deref, (vref, x)) t) - // The compiler ValRef's into fslib stored in env.fs break certain invariants that hold elsewhere, + // The compiler's ValRef's in TcGlobals.fs that refer to things in FSharp.Core break certain invariants that hold elsewhere, // because they dereference to point to Val's from signatures rather than Val's from implementations. - // Thus a backup alternative resolution technique is needed for these. + // Thus a backup alternative resolution technique is needed for these when processing the FSharp.Core implementation files + // holding these items. This resolution must be able to distinguish between overloaded methods, so we use + // XmlDocSigOfVal as a cheap hack to get a unique item of data for a value. let valInfosForFslib = - lazy ( - let dict = Dictionary<_, _>() + LazyWithContext<_, TcGlobals>.Create ((fun g -> + let dict = + Dictionary<(ValRef * ValLinkageFullKey), (ValRef * ValInfo)> + (HashIdentity.FromFunctions + (fun (_: ValRef, k: ValLinkageFullKey) -> hash k.PartialKey) + (fun (v1, k1) (v2, k2) -> + k1.PartialKey = k2.PartialKey && + // dismbiguate overloads, somewhat low-perf but only use for a handful of overloads in FSharp.Core + match k1.TypeForLinkage, k2.TypeForLinkage with + | Some _, Some _ -> + let sig1 = XmlDocSigOfVal g true "" v1.Deref + let sig2 = XmlDocSigOfVal g true "" v2.Deref + (sig1 = sig2) + | None, None -> true + | _ -> false)) for (vref, _x) as p in entries do - let vkey = vref.Deref.GetLinkagePartialKey() + let vkey = (vref, vref.Deref.GetLinkageFullKey()) + if dict.ContainsKey vkey then + failwithf "dictionary already contains key %A" vkey dict.Add(vkey, p) |> ignore - dict) + dict), id) member x.Entries = valInfoTable.Force().Values @@ -155,7 +172,8 @@ type ValInfos(entries) = member x.TryFind (v: ValRef) = valInfoTable.Force().TryFind v.Deref - member x.TryFindForFslib (v: ValRef) = valInfosForFslib.Force().TryGetValue(v.Deref.GetLinkagePartialKey()) + member x.TryFindForFslib (g, vref: ValRef) = + valInfosForFslib.Force(g).TryGetValue((vref, vref.Deref.GetLinkageFullKey())) type ModuleInfo = { ValInfos: ValInfos @@ -617,7 +635,7 @@ let GetInfoForNonLocalVal cenv env (vref: ValRef) = //dprintn ("\n\n*** Optimization info for value "+n+" from module "+(full_name_of_nlpath smv)+" not found, module contains values: "+String.concat ", " (NameMap.domainL structInfo.ValInfos)) //System.Diagnostics.Debug.Assert(false, sprintf "Break for module %s, value %s" (full_name_of_nlpath smv) n) if cenv.g.compilingFslib then - match structInfo.ValInfos.TryFindForFslib vref with + match structInfo.ValInfos.TryFindForFslib (cenv.g, vref) with | true, ninfo -> snd ninfo | _ -> UnknownValInfo else @@ -2413,7 +2431,7 @@ and OptimizeWhileLoop cenv env (spWhile, marker, e1, e2, m) = and OptimizeTraitCall cenv env (traitInfo, args, m) = // Resolve the static overloading early (during the compulsory rewrite phase) so we can inline. - match ConstraintSolver.CodegenWitnessThatTypeSupportsTraitConstraint cenv.TcVal cenv.g cenv.amap m traitInfo args with + match ConstraintSolver.CodegenWitnessForTraitConstraint cenv.TcVal cenv.g cenv.amap m traitInfo args with | OkResult (_, Some expr) -> OptimizeExpr cenv env expr @@ -2946,7 +2964,6 @@ and OptimizeLambdas (vspec: Val option) cenv env topValInfo e ety = let expr2 = mkMemberLambdas m tps ctorThisValOpt None vsl (bodyR, bodyty) CurriedLambdaValue (lambdaId, arities, bsize, expr2, ety) - let estimatedSize = match vspec with | Some v when v.IsCompiledAsTopLevel -> methodDefnTotalSize diff --git a/src/fsharp/PostInferenceChecks.fs b/src/fsharp/PostInferenceChecks.fs index 521d623a4e9..e7ff9c60e70 100644 --- a/src/fsharp/PostInferenceChecks.fs +++ b/src/fsharp/PostInferenceChecks.fs @@ -197,8 +197,11 @@ type cenv = isLastCompiland : bool*bool isInternalTestSpanStackReferring: bool // outputs - mutable usesQuotations : bool - mutable entryPointGiven: bool } + mutable usesQuotations: bool + mutable entryPointGiven: bool + + /// Callback required for quotation generation + tcVal: ConstraintSolver.TcValF } /// Check if the value is an argument of a function let IsValArgument env (v: Val) = @@ -939,7 +942,7 @@ and CheckExpr (cenv: cenv) (env: env) origExpr (context: PermitByRefExpr) : Limi // Translate to quotation data try - let qscope = QuotationTranslator.QuotationGenerationScope.Create (g, cenv.amap, cenv.viewCcu, QuotationTranslator.IsReflectedDefinition.No) + let qscope = QuotationTranslator.QuotationGenerationScope.Create (g, cenv.amap, cenv.viewCcu, cenv.tcVal, QuotationTranslator.IsReflectedDefinition.No) let qdata = QuotationTranslator.ConvExprPublic qscope QuotationTranslator.QuotationTranslationEnv.Empty ast let typeDefs, spliceTypes, spliceExprs = qscope.Close() match savedConv.Value with @@ -1718,7 +1721,7 @@ and CheckBinding cenv env alwaysCheckNoReraise context (TBind(v, bindRhs, _) as | Expr.TyLambda (_, tps, b, _, _) -> tps, b, applyForallTy g ety (List.map mkTyparTy tps) | _ -> [], bindRhs, ety let env = QuotationTranslator.QuotationTranslationEnv.Empty.BindTypars tps - let qscope = QuotationTranslator.QuotationGenerationScope.Create (g, cenv.amap, cenv.viewCcu, QuotationTranslator.IsReflectedDefinition.Yes) + let qscope = QuotationTranslator.QuotationGenerationScope.Create (g, cenv.amap, cenv.viewCcu, cenv.tcVal, QuotationTranslator.IsReflectedDefinition.Yes) QuotationTranslator.ConvExprPublic qscope env taue |> ignore let _, _, argExprs = qscope.Close() if not (isNil argExprs) then @@ -2256,7 +2259,7 @@ and CheckModuleSpec cenv env x = let env = { env with reflect = env.reflect || HasFSharpAttribute cenv.g cenv.g.attrib_ReflectedDefinitionAttribute mspec.Attribs } CheckDefnInModule cenv env rhs -let CheckTopImpl (g, amap, reportErrors, infoReader, internalsVisibleToPaths, viewCcu, denv, mexpr, extraAttribs, (isLastCompiland: bool*bool), isInternalTestSpanStackReferring) = +let CheckTopImpl (g, amap, reportErrors, infoReader, internalsVisibleToPaths, viewCcu, tcVal, denv, mexpr, extraAttribs, (isLastCompiland: bool*bool), isInternalTestSpanStackReferring) = let cenv = { g =g reportErrors=reportErrors @@ -2272,7 +2275,8 @@ let CheckTopImpl (g, amap, reportErrors, infoReader, internalsVisibleToPaths, vi viewCcu= viewCcu isLastCompiland=isLastCompiland isInternalTestSpanStackReferring = isInternalTestSpanStackReferring - entryPointGiven=false} + entryPointGiven=false + tcVal = tcVal} // Certain type equality checks go faster if these TyconRefs are pre-resolved. // This is because pre-resolving allows tycon equality to be determined by pointer equality on the entities. @@ -2295,10 +2299,10 @@ let CheckTopImpl (g, amap, reportErrors, infoReader, internalsVisibleToPaths, vi reflect=false external=false returnScope = 0 - isInAppExpr = false } + isInAppExpr = false } CheckModuleExpr cenv env mexpr CheckAttribs cenv env extraAttribs - if cenv.usesQuotations && QuotationTranslator.QuotationGenerationScope.ComputeQuotationFormat g = QuotationTranslator.QuotationSerializationFormat.FSharp_20_Plus then + if cenv.usesQuotations && not (QuotationTranslator.QuotationGenerationScope.ComputeQuotationFormat(g).SupportsDeserializeEx) then viewCcu.UsesFSharp20PlusQuotations <- true cenv.entryPointGiven, cenv.anonRecdTypes diff --git a/src/fsharp/PostInferenceChecks.fsi b/src/fsharp/PostInferenceChecks.fsi index 25c6bf3ac35..e6b01b4e65a 100644 --- a/src/fsharp/PostInferenceChecks.fsi +++ b/src/fsharp/PostInferenceChecks.fsi @@ -11,4 +11,4 @@ open FSharp.Compiler.Tastops open FSharp.Compiler.TcGlobals /// Perform the checks on the TAST for a file after type inference is complete. -val CheckTopImpl : TcGlobals * ImportMap * bool * InfoReader * CompilationPath list * CcuThunk * DisplayEnv * ModuleOrNamespaceExprWithSig * Attribs * (bool * bool) * isInternalTestSpanStackReferring: bool -> bool * StampMap +val CheckTopImpl : TcGlobals * ImportMap * bool * InfoReader * CompilationPath list * CcuThunk * ConstraintSolver.TcValF * DisplayEnv * ModuleOrNamespaceExprWithSig * Attribs * (bool * bool) * isInternalTestSpanStackReferring: bool -> bool * StampMap diff --git a/src/fsharp/PrettyNaming.fs b/src/fsharp/PrettyNaming.fs index 4c11b9054d3..d37604ac0fd 100755 --- a/src/fsharp/PrettyNaming.fs +++ b/src/fsharp/PrettyNaming.fs @@ -697,4 +697,6 @@ module public FSharp.Compiler.PrettyNaming | _ -> Some (defaultArgName, actualArgValue)) mangleProvidedTypeName (nm, nonDefaultArgs) - let outArgCompilerGeneratedName = "outArg" \ No newline at end of file + let outArgCompilerGeneratedName = "outArg" + + let ExtraWitnessMethodName nm = nm + "WithWitnesses" \ No newline at end of file diff --git a/src/fsharp/QuotationPickler.fs b/src/fsharp/QuotationPickler.fs index 90a9e299947..7b951630de6 100644 --- a/src/fsharp/QuotationPickler.fs +++ b/src/fsharp/QuotationPickler.fs @@ -46,14 +46,13 @@ type VarData = vType: TypeData vMutable: bool } -type FieldData = NamedTypeData * string -type RecdFieldData = NamedTypeData * string type PropInfoData = NamedTypeData * string * TypeData * TypeData list type CombOp = | AppOp | CondOp | ModuleValueOp of NamedTypeData * string * bool + | ModuleValueWOp of NamedTypeData * string * bool * string * int | LetRecOp | LetRecCombOp | LetOp @@ -83,6 +82,7 @@ type CombOp = | FieldGetOp of NamedTypeData * string | CtorCallOp of CtorData | MethodCallOp of MethodData + | MethodCallWOp of MethodData * MethodData * int | CoerceOp | NewArrayOp | DelegateOp @@ -126,7 +126,11 @@ let mkQuoteRaw40 (a) = QuoteRawExpr (a) let mkCond (x1, x2, x3) = CombExpr(CondOp, [], [x1;x2;x3]) -let mkModuleValueApp (tcref, nm, isProp, tyargs, args: ExprData list list) = CombExpr(ModuleValueOp(tcref, nm, isProp), tyargs, List.concat args) +let mkModuleValueApp (tcref, nm, isProp, tyargs, args: ExprData list) = + CombExpr(ModuleValueOp(tcref, nm, isProp), tyargs, args) + +let mkModuleValueWApp (tcref, nm, isProp, nmW, nWitnesses, tyargs, args: ExprData list) = + CombExpr(ModuleValueWOp(tcref, nm, isProp, nmW, nWitnesses), tyargs, args) let mkTuple (ty, x) = CombExpr(TupleMkOp, [ty], x) @@ -146,15 +150,15 @@ let mkLetRec (ves, body) = let mkRecdMk (n, tys, args) = CombExpr(RecdMkOp n, tys, args) -let mkRecdGet ((d1, d2), tyargs, args) = CombExpr(RecdGetOp(d1, d2), tyargs, args) +let mkRecdGet (d1, d2, tyargs, args) = CombExpr(RecdGetOp(d1, d2), tyargs, args) -let mkRecdSet ((d1, d2), tyargs, args) = CombExpr(RecdSetOp(d1, d2), tyargs, args) +let mkRecdSet (d1, d2, tyargs, args) = CombExpr(RecdSetOp(d1, d2), tyargs, args) -let mkUnion ((d1, d2), tyargs, args) = CombExpr(SumMkOp(d1, d2), tyargs, args) +let mkUnion (d1, d2, tyargs, args) = CombExpr(SumMkOp(d1, d2), tyargs, args) -let mkUnionFieldGet ((d1, d2, d3), tyargs, arg) = CombExpr(SumFieldGetOp(d1, d2, d3), tyargs, [arg]) +let mkUnionFieldGet (d1, d2, d3, tyargs, arg) = CombExpr(SumFieldGetOp(d1, d2, d3), tyargs, [arg]) -let mkUnionCaseTagTest ((d1, d2), tyargs, arg) = CombExpr(SumTagTestOp(d1, d2), tyargs, [arg]) +let mkUnionCaseTagTest (d1, d2, tyargs, arg) = CombExpr(SumTagTestOp(d1, d2), tyargs, [arg]) let mkTupleGet (ty, n, e) = CombExpr(TupleGetOp n, [ty], [e]) @@ -216,14 +220,16 @@ let mkPropGet (d, tyargs, args) = CombExpr(PropGetOp(d), tyargs, args) let mkPropSet (d, tyargs, args) = CombExpr(PropSetOp(d), tyargs, args) -let mkFieldGet ((d1, d2), tyargs, args) = CombExpr(FieldGetOp(d1, d2), tyargs, args) +let mkFieldGet (d1, d2, tyargs, args) = CombExpr(FieldGetOp(d1, d2), tyargs, args) -let mkFieldSet ((d1, d2), tyargs, args) = CombExpr(FieldSetOp(d1, d2), tyargs, args) +let mkFieldSet (d1, d2, tyargs, args) = CombExpr(FieldSetOp(d1, d2), tyargs, args) let mkCtorCall (d, tyargs, args) = CombExpr(CtorCallOp(d), tyargs, args) let mkMethodCall (d, tyargs, args) = CombExpr(MethodCallOp(d), tyargs, args) +let mkMethodCallW (d1, d2, d3, tyargs, args) = CombExpr(MethodCallWOp(d1, d2, d3), tyargs, args) + let mkAttributedExpression(e, attr) = AttrExpr(e, [attr]) let isAttributedExpression e = match e with AttrExpr(_, _) -> true | _ -> false @@ -410,7 +416,11 @@ let p_PropInfoData a st = let p_CombOp x st = match x with | CondOp -> p_byte 0 st - | ModuleValueOp (x, y, z) -> p_byte 1 st; p_tup3 p_NamedType p_string p_bool (x, y, z) st + | ModuleValueOp (x, y, z) -> + p_byte 1 st + p_NamedType x st + p_string y st + p_bool z st | LetRecOp -> p_byte 2 st | RecdMkOp a -> p_byte 3 st; p_NamedType a st | RecdGetOp (x, y) -> p_byte 4 st; p_recdFieldSpec (x, y) st @@ -457,6 +467,18 @@ let p_CombOp x st = | TryFinallyOp -> p_byte 47 st | TryWithOp -> p_byte 48 st | ExprSetOp -> p_byte 49 st + | MethodCallWOp (a, b, c) -> + p_byte 50 st + p_MethodData a st + p_MethodData b st + p_int c st + | ModuleValueWOp (x, y, z, nmW, nWitnesses) -> + p_byte 51 st + p_string nmW st + p_int nWitnesses st + p_NamedType x st + p_string y st + p_bool z st let rec p_expr x st = match x with @@ -475,7 +497,7 @@ type ModuleDefnData = IsProperty: bool } type MethodBaseData = - | ModuleDefn of ModuleDefnData + | ModuleDefn of ModuleDefnData * (string * int) option | Method of MethodData | Ctor of CtorData @@ -483,11 +505,18 @@ let pickle = pickle_obj p_expr let p_MethodBase x st = match x with - | ModuleDefn md -> + | ModuleDefn (md, None) -> p_byte 0 st p_NamedType md.Module st p_string md.Name st p_bool md.IsProperty st + | ModuleDefn (md, Some (nmW, nWitnesses)) -> + p_byte 3 st + p_string nmW st + p_int nWitnesses st + p_NamedType md.Module st + p_string md.Name st + p_bool md.IsProperty st | Method md -> p_byte 1 st p_MethodData md st diff --git a/src/fsharp/QuotationPickler.fsi b/src/fsharp/QuotationPickler.fsi index ffe23215886..7ac1f1ad996 100644 --- a/src/fsharp/QuotationPickler.fsi +++ b/src/fsharp/QuotationPickler.fsi @@ -47,12 +47,10 @@ type ModuleDefnData = IsProperty: bool } type MethodBaseData = - | ModuleDefn of ModuleDefnData + | ModuleDefn of ModuleDefnData * (string * int) option | Method of MethodData | Ctor of CtorData -type FieldData = NamedTypeData * string -type RecdFieldData = NamedTypeData * string type PropInfoData = NamedTypeData * string * TypeData * TypeData list val mkVar : int -> ExprData @@ -63,15 +61,16 @@ val mkLambda : VarData * ExprData -> ExprData val mkQuote : ExprData -> ExprData val mkQuoteRaw40 : ExprData -> ExprData // only available for FSharp.Core 4.4.0.0+ val mkCond : ExprData * ExprData * ExprData -> ExprData -val mkModuleValueApp : NamedTypeData * string * bool * TypeData list * ExprData list list -> ExprData +val mkModuleValueApp : NamedTypeData * string * bool * TypeData list * ExprData list -> ExprData +val mkModuleValueWApp : NamedTypeData * string * bool * string * int * TypeData list * ExprData list -> ExprData val mkLetRec : (VarData * ExprData) list * ExprData -> ExprData val mkLet : (VarData * ExprData) * ExprData -> ExprData val mkRecdMk : NamedTypeData * TypeData list * ExprData list -> ExprData -val mkRecdGet : RecdFieldData * TypeData list * ExprData list -> ExprData -val mkRecdSet : RecdFieldData * TypeData list * ExprData list -> ExprData -val mkUnion : (NamedTypeData * string) * TypeData list * ExprData list -> ExprData -val mkUnionFieldGet : (NamedTypeData * string * int) * TypeData list * ExprData -> ExprData -val mkUnionCaseTagTest : (NamedTypeData * string) * TypeData list * ExprData -> ExprData +val mkRecdGet : NamedTypeData * string * TypeData list * ExprData list -> ExprData +val mkRecdSet : NamedTypeData * string * TypeData list * ExprData list -> ExprData +val mkUnion : NamedTypeData * string * TypeData list * ExprData list -> ExprData +val mkUnionFieldGet : NamedTypeData * string * int * TypeData list * ExprData -> ExprData +val mkUnionCaseTagTest : NamedTypeData * string * TypeData list * ExprData -> ExprData val mkTuple : TypeData * ExprData list -> ExprData val mkTupleGet : TypeData * int * ExprData -> ExprData val mkCoerce : TypeData * ExprData -> ExprData @@ -104,10 +103,11 @@ val mkTryWith : ExprData * VarData * ExprData * VarData * ExprData -> ExprData val mkDelegate : TypeData * ExprData -> ExprData val mkPropGet : PropInfoData * TypeData list * ExprData list -> ExprData val mkPropSet : PropInfoData * TypeData list * ExprData list -> ExprData -val mkFieldGet : FieldData * TypeData list * ExprData list -> ExprData -val mkFieldSet : FieldData * TypeData list * ExprData list -> ExprData +val mkFieldGet : NamedTypeData * string * TypeData list * ExprData list -> ExprData +val mkFieldSet : NamedTypeData * string * TypeData list * ExprData list -> ExprData val mkCtorCall : CtorData * TypeData list * ExprData list -> ExprData val mkMethodCall : MethodData * TypeData list * ExprData list -> ExprData +val mkMethodCallW : MethodData * MethodData * int * TypeData list * ExprData list -> ExprData val mkAttributedExpression : ExprData * ExprData -> ExprData val pickle : (ExprData -> byte[]) val isAttributedExpression : ExprData -> bool diff --git a/src/fsharp/QuotationTranslator.fs b/src/fsharp/QuotationTranslator.fs index ecbe10d5ad2..d6f443e532d 100644 --- a/src/fsharp/QuotationTranslator.fs +++ b/src/fsharp/QuotationTranslator.fs @@ -28,14 +28,19 @@ type IsReflectedDefinition = [] type QuotationSerializationFormat = - /// Indicates that type references are emitted as integer indexes into a supplied table - | FSharp_40_Plus - | FSharp_20_Plus + { + /// Indicates that witness parameters are recorded + SupportsWitnesses: bool + + /// Indicates that type references are emitted as integer indexes into a supplied table + SupportsDeserializeEx: bool + } type QuotationGenerationScope = { g: TcGlobals amap: Import.ImportMap scope: CcuThunk + tcVal : ConstraintSolver.TcValF // Accumulate the references to type definitions referencedTypeDefs: ResizeArray referencedTypeDefsTable: Dictionary @@ -47,10 +52,11 @@ type QuotationGenerationScope = quotationFormat : QuotationSerializationFormat mutable emitDebugInfoInQuotations : bool } - static member Create (g: TcGlobals, amap, scope, isReflectedDefinition) = + static member Create (g: TcGlobals, amap, scope, tcVal, isReflectedDefinition) = { g = g scope = scope amap = amap + tcVal = tcVal referencedTypeDefs = new ResizeArray<_>() referencedTypeDefsTable = new Dictionary<_, _>() typeSplices = new ResizeArray<_>() @@ -65,11 +71,8 @@ type QuotationGenerationScope = cenv.exprSplices |> ResizeArray.toList static member ComputeQuotationFormat g = - let deserializeExValRef = ValRefForIntrinsic g.deserialize_quoted_FSharp_40_plus_info - if deserializeExValRef.TryDeref.IsSome then - QuotationSerializationFormat.FSharp_40_Plus - else - QuotationSerializationFormat.FSharp_20_Plus + { SupportsDeserializeEx = (ValRefForIntrinsic g.deserialize_quoted_FSharp_40_plus_info).TryDeref.IsSome + SupportsWitnesses = (ValRefForIntrinsic g.call_with_witnesses_info).TryDeref.IsSome } type QuotationTranslationEnv = { @@ -81,6 +84,9 @@ type QuotationTranslationEnv = /// Map from typar stamps to binding index tyvs: StampMap + /// Indicates this is a witness arg we we disable further generation of witnesses + isWitness: bool + // Map for values bound by the // 'let v = isinst e in .... if nonnull v then ...v .... ' // construct arising out the compilation of pattern matching. We decode these back to the form @@ -94,6 +100,7 @@ type QuotationTranslationEnv = { vs = ValMap<_>.Empty nvs = 0 tyvs = Map.empty + isWitness = false isinstVals = ValMap<_>.Empty substVals = ValMap<_>.Empty } @@ -241,18 +248,18 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP. let (numEnclTypeArgs, _, isNewObj, valUseFlags, isSelfInit, takesInstanceArg, isPropGet, isPropSet) = GetMemberCallInfo cenv.g (vref, vFlags) - let isMember, tps, curriedArgInfos, retTy = + let isMember, tps, cxs, curriedArgInfos, retTy = match vref.MemberInfo with | Some _ when not vref.IsExtensionMember -> // This is an application of a member method // We only count one argument block for these. - let tps, curriedArgInfos, retTy, _ = GetTypeOfIntrinsicMemberInCompiledForm cenv.g vref - true, tps, curriedArgInfos, retTy + let tps, cxs, curriedArgInfos, retTy, _ = GetTypeOfIntrinsicMemberInCompiledForm cenv.g vref + true, tps, cxs, curriedArgInfos, retTy | _ -> // This is an application of a module value or extension member let arities = arityOfVal vref.Deref - let tps, curriedArgInfos, retTy, _ = GetTopValTypeInCompiledForm cenv.g arities vref.Type m - false, tps, curriedArgInfos, retTy + let tps, cxs, curriedArgInfos, retTy, _ = GetTopValTypeInCompiledForm cenv.g arities vref.Type m + false, tps, cxs, curriedArgInfos, retTy // Compute the object arguments as they appear in a compiled call // Strip off the object argument, if any. The curriedArgInfos are already adjusted to compiled member form @@ -300,26 +307,34 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP. else tryDestRefTupleExpr arg)) if verboseCReflect then - dprintfn "vref.DisplayName = %A, after unit adjust, #untupledCurriedArgs = %A, #curriedArgInfos = %d" vref.DisplayName (List.map List.length untupledCurriedArgs) curriedArgInfos.Length + dprintfn "vref.DisplayName = %A , after unit adjust, #untupledCurriedArgs = %A, #curriedArgInfos = %d" vref.DisplayName (List.map List.length untupledCurriedArgs) curriedArgInfos.Length + + let witnessArgTys = GenWitnessTys cenv.g cxs + let witnessArgs = + if cenv.g.generateWitnesses && not env.isWitness then + ConstraintSolver.CodegenWitnessesForTyparInst cenv.tcVal cenv.g cenv.amap m tps tyargs + |> CommitOperationResult + else + [] + let subCall = if isMember then - // This is an application of a member method - // We only count one argument block for these. - let callArgs = (objArgs :: untupledCurriedArgs) |> List.concat let parentTyconR = ConvTyconRef cenv vref.TopValDeclaringEntity m let isNewObj = isNewObj || valUseFlags || isSelfInit // The signature types are w.r.t. to the formal context let envinner = BindFormalTypars env tps let argTys = curriedArgInfos |> List.concat |> List.map fst + let witnessArgTypesR = ConvTypes cenv envinner m witnessArgTys let methArgTypesR = ConvTypes cenv envinner m argTys let methRetTypeR = ConvReturnType cenv envinner m retTy let methName = vref.CompiledName let numGenericArgs = tyargs.Length - numEnclTypeArgs - ConvObjectModelCall cenv env m (isPropGet, isPropSet, isNewObj, parentTyconR, methArgTypesR, methRetTypeR, methName, tyargs, numGenericArgs, callArgs) + ConvObjectModelCall cenv env m (isPropGet, isPropSet, isNewObj, parentTyconR, witnessArgTypesR, methArgTypesR, methRetTypeR, methName, tyargs, numGenericArgs, objArgs, witnessArgs, untupledCurriedArgs) else // This is an application of the module value. - ConvModuleValueApp cenv env m vref tyargs untupledCurriedArgs + ConvModuleValueApp cenv env m vref tyargs witnessArgs untupledCurriedArgs + match curriedArgs, curriedArgInfos with // static member and module value unit argument elimination | [arg: Expr], [[]] -> @@ -382,7 +397,7 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP. | Expr.Quote (ast, _, _, _, ety) -> // F# 2.0-3.1 had a bug with nested 'raw' quotations. F# 4.0 + FSharp.Core 4.4.0.0+ allows us to do the right thing. - if cenv.quotationFormat = QuotationSerializationFormat.FSharp_40_Plus && + if cenv.quotationFormat.SupportsDeserializeEx && // Look for a 'raw' quotation tyconRefEq cenv.g (tcrefOfAppTy cenv.g ety) cenv.g.raw_expr_tcr then @@ -414,16 +429,15 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP. | Expr.Op (op, tyargs, args, m) -> match op, tyargs, args with | TOp.UnionCase ucref, _, _ -> - let mkR = ConvUnionCaseRef cenv ucref m + let tcR, s = ConvUnionCaseRef cenv ucref m let tyargsR = ConvTypes cenv env m tyargs let argsR = ConvExprs cenv env args - QP.mkUnion(mkR, tyargsR, argsR) - + QP.mkUnion(tcR, s, tyargsR, argsR) | TOp.Tuple tupInfo, tyargs, _ -> let tyR = ConvType cenv env m (mkAnyTupledTy cenv.g tupInfo tyargs) let argsR = ConvExprs cenv env args - QP.mkTuple(tyR, argsR) // TODO: propagate to quotations + QP.mkTuple(tyR, argsR) | TOp.Recd (_, tcref), _, _ -> let rgtypR = ConvTyconRef cenv tcref m @@ -443,7 +457,7 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP. let rgtypR = ConvILTypeRef cenv tref let tyargsR = ConvTypes cenv env m tyargs let argsR = ConvExprs cenv env args - QP.mkRecdGet((rgtypR, anonInfo.SortedNames.[n]), tyargsR, argsR) + QP.mkRecdGet(rgtypR, anonInfo.SortedNames.[n], tyargsR, argsR) | TOp.UnionCaseFieldGet (ucref, n), tyargs, [e] -> ConvUnionFieldGet cenv env m ucref n tyargs e @@ -475,7 +489,7 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP. let tyargsR = ConvTypes cenv env m enclTypeArgs let parentTyconR = ConvILTypeRefUnadjusted cenv m fspec.DeclaringTypeRef let argsR = ConvLValueArgs cenv env args - QP.mkFieldSet( (parentTyconR, fspec.Name), tyargsR, argsR) + QP.mkFieldSet(parentTyconR, fspec.Name, tyargsR, argsR) | TOp.ILAsm ([ AI_ceq ], _), _, [arg1;arg2] -> let ty = tyOfExpr cenv.g arg1 @@ -506,15 +520,15 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP. | TOp.ValFieldSet rfref, _tinst, args -> let argsR = ConvLValueArgs cenv env args let tyargsR = ConvTypes cenv env m tyargs - let ((_parentTyconR, fldOrPropName) as projR) = ConvRecdFieldRef cenv rfref m + let parentTyconR, fldOrPropName = ConvRecdFieldRef cenv rfref m if rfref.TyconRef.IsRecordTycon then - QP.mkRecdSet(projR, tyargsR, argsR) + QP.mkRecdSet(parentTyconR, fldOrPropName, tyargsR, argsR) else let fspec = rfref.RecdField let tcref = rfref.TyconRef let parentTyconR = ConvTyconRef cenv tcref m if useGenuineField tcref.Deref fspec then - QP.mkFieldSet( projR, tyargsR, argsR) + QP.mkFieldSet(parentTyconR, fldOrPropName, tyargsR, argsR) else let envinner = BindFormalTypars env (tcref.TyparsNoRange) let propRetTypeR = ConvType cenv envinner m fspec.FormalType @@ -586,7 +600,7 @@ and private ConvExprCore cenv (env : QuotationTranslationEnv) (expr: Expr) : QP. let isPropGet = isProp && methName.StartsWithOrdinal("get_") let isPropSet = isProp && methName.StartsWithOrdinal("set_") let tyargs = (enclTypeArgs@methTypeArgs) - ConvObjectModelCall cenv env m (isPropGet, isPropSet, isNewObj, parentTyconR, methArgTypesR, methRetTypeR, methName, tyargs, methTypeArgs.Length, callArgs) + ConvObjectModelCall cenv env m (isPropGet, isPropSet, isNewObj, parentTyconR, [], methArgTypesR, methRetTypeR, methName, tyargs, methTypeArgs.Length, [], [], [callArgs]) | TOp.TryFinally _, [_resty], [Expr.Lambda (_, _, _, [_], e1, _, _); Expr.Lambda (_, _, _, [_], e2, _, _)] -> QP.mkTryFinally(ConvExpr cenv env e1, ConvExpr cenv env e2) @@ -620,14 +634,13 @@ and ConvLdfld cenv env m (fspec: ILFieldSpec) enclTypeArgs args = let tyargsR = ConvTypes cenv env m enclTypeArgs let parentTyconR = ConvILTypeRefUnadjusted cenv m fspec.DeclaringTypeRef let argsR = ConvLValueArgs cenv env args - QP.mkFieldGet( (parentTyconR, fspec.Name), tyargsR, argsR) + QP.mkFieldGet(parentTyconR, fspec.Name, tyargsR, argsR) and ConvUnionFieldGet cenv env m ucref n tyargs e = let tyargsR = ConvTypes cenv env m tyargs let tcR, s = ConvUnionCaseRef cenv ucref m - let projR = (tcR, s, n) let eR = ConvLValueExpr cenv env e - QP.mkUnionFieldGet(projR, tyargsR, eR) + QP.mkUnionFieldGet(tcR, s, n, tyargsR, eR) and ConvClassOrRecdFieldGet cenv env m rfref tyargs args = EmitDebugInfoIfNecessary cenv env m (ConvClassOrRecdFieldGetCore cenv env m rfref tyargs args) @@ -635,14 +648,14 @@ and ConvClassOrRecdFieldGet cenv env m rfref tyargs args = and private ConvClassOrRecdFieldGetCore cenv env m rfref tyargs args = let tyargsR = ConvTypes cenv env m tyargs let argsR = ConvLValueArgs cenv env args - let ((parentTyconR, fldOrPropName) as projR) = ConvRecdFieldRef cenv rfref m + let (parentTyconR, fldOrPropName) = ConvRecdFieldRef cenv rfref m if rfref.TyconRef.IsRecordTycon then - QP.mkRecdGet(projR, tyargsR, argsR) + QP.mkRecdGet(parentTyconR, fldOrPropName, tyargsR, argsR) else let fspec = rfref.RecdField let tcref = rfref.TyconRef if useGenuineField tcref.Deref fspec then - QP.mkFieldGet(projR, tyargsR, argsR) + QP.mkFieldGet(parentTyconR, fldOrPropName, tyargsR, argsR) else let envinner = BindFormalTypars env tcref.TyparsNoRange let propRetTypeR = ConvType cenv envinner m fspec.FormalType @@ -679,6 +692,14 @@ and ConvLValueArgs cenv env args = | obj :: rest -> ConvLValueExpr cenv env obj :: ConvExprs cenv env rest | [] -> [] +and ConvWitnessArgs cenv env witnessArgs = + let env = { env with isWitness = true } + witnessArgs |> List.map (fun arg -> + match arg with + | Choice1Of2 _witnessInfo -> failwith "TODO: ReflectedDefinition of 'let inline' quotations that utilise witnesses" + | Choice2Of2 arg -> ConvExpr cenv env arg + ) + and ConvLValueExpr cenv env expr = EmitDebugInfoIfNecessary cenv env expr.Range (ConvLValueExprCore cenv env expr) @@ -705,46 +726,79 @@ and ConvLValueExprCore cenv env expr = and ConvObjectModelCall cenv env m callInfo = EmitDebugInfoIfNecessary cenv env m (ConvObjectModelCallCore cenv env m callInfo) -and ConvObjectModelCallCore cenv env m (isPropGet, isPropSet, isNewObj, parentTyconR, methArgTypesR, methRetTypeR, methName, tyargs, numGenericArgs, callArgs) = +and ConvObjectModelCallCore cenv env m (isPropGet, isPropSet, isNewObj, parentTyconR, witnessArgTypesR, methArgTypesR, methRetTypeR, methName, tyargs, numGenericArgs, objArgs, witnessArgs, untupledCurriedArgs) = let tyargsR = ConvTypes cenv env m tyargs + let callArgs = (objArgs::untupledCurriedArgs) |> List.concat let callArgsR = ConvLValueArgs cenv env callArgs - + let witnessArgsR = ConvWitnessArgs cenv env witnessArgs + let allArgsR = witnessArgsR @ callArgsR + if isPropGet || isPropSet then + assert witnessArgTypesR.IsEmpty let propName = ChopPropertyName methName if isPropGet then - QP.mkPropGet( (parentTyconR, propName, methRetTypeR, methArgTypesR), tyargsR, callArgsR) + QP.mkPropGet( (parentTyconR, propName, methRetTypeR, methArgTypesR), tyargsR, allArgsR) else let args, propTy = List.frontAndBack methArgTypesR - QP.mkPropSet( (parentTyconR, propName, propTy, args), tyargsR, callArgsR) + QP.mkPropSet( (parentTyconR, propName, propTy, args), tyargsR, allArgsR) elif isNewObj then + assert witnessArgTypesR.IsEmpty let ctorR : QuotationPickler.CtorData = { ctorParent = parentTyconR ctorArgTypes = methArgTypesR } - QP.mkCtorCall(ctorR, tyargsR, callArgsR) + QP.mkCtorCall(ctorR, tyargsR, allArgsR) + + elif witnessArgTypesR.IsEmpty then - else let methR : QuotationPickler.MethodData = { methParent = parentTyconR methArgTypes = methArgTypesR methRetType = methRetTypeR methName = methName numGenericArgs = numGenericArgs } - QP.mkMethodCall(methR, tyargsR, callArgsR) -and ConvModuleValueApp cenv env m (vref: ValRef) tyargs (args: Expr list list) = - EmitDebugInfoIfNecessary cenv env m (ConvModuleValueAppCore cenv env m vref tyargs args) + QP.mkMethodCall(methR, tyargsR, allArgsR) + + else + + // The old method entry point + let methR: QuotationPickler.MethodData = + { methParent = parentTyconR + methArgTypes = methArgTypesR + methRetType = methRetTypeR + methName = methName + numGenericArgs = numGenericArgs } + + // The witness-passing method entry point + let methWR: QuotationPickler.MethodData = + { methParent = parentTyconR + methArgTypes = witnessArgTypesR @ methArgTypesR + methRetType = methRetTypeR + methName = ExtraWitnessMethodName methName + numGenericArgs = numGenericArgs } + + QP.mkMethodCallW(methR, methWR, List.length witnessArgTypesR, tyargsR, allArgsR) + +and ConvModuleValueApp cenv env m (vref:ValRef) tyargs witnessArgs (args: Expr list list) = + EmitDebugInfoIfNecessary cenv env m (ConvModuleValueAppCore cenv env m vref tyargs witnessArgs args) -and ConvModuleValueAppCore cenv env m (vref: ValRef) tyargs (args: Expr list list) = +and ConvModuleValueAppCore cenv env m (vref:ValRef) tyargs witnessArgs (curriedArgs: Expr list list) = match vref.DeclaringEntity with - | ParentNone -> failwith "ConvModuleValueApp" + | ParentNone -> failwith "ConvModuleValueAppCore" | Parent(tcref) -> let isProperty = IsCompiledAsStaticProperty cenv.g vref.Deref let tcrefR = ConvTyconRef cenv tcref m let tyargsR = ConvTypes cenv env m tyargs let nm = vref.CompiledName - let argsR = List.map (ConvExprs cenv env) args - QP.mkModuleValueApp(tcrefR, nm, isProperty, tyargsR, argsR) + let witnessArgsR = ConvWitnessArgs cenv env witnessArgs + let uncurriedArgsR = ConvExprs cenv env (List.concat curriedArgs) + let allArgsR = witnessArgsR @ uncurriedArgsR + let nWitnesses = witnessArgs.Length + if nWitnesses = 0 then + QP.mkModuleValueApp(tcrefR, nm, isProperty, tyargsR, allArgsR) + else + QP.mkModuleValueWApp(tcrefR, nm, isProperty, ExtraWitnessMethodName nm, nWitnesses, tyargsR, allArgsR) and ConvExprs cenv env args = List.map (ConvExpr cenv env) args @@ -772,10 +826,19 @@ and private ConvValRefCore holeOk cenv env m (vref: ValRef) tyargs = // References to local values are embedded by value if not holeOk then wfail(Error(FSComp.SR.crefNoSetOfHole(), m)) let idx = cenv.exprSplices.Count - cenv.exprSplices.Add((mkCallLiftValueWithName cenv.g m vty v.LogicalName (exprForValRef m vref), m)) + let liftExpr = mkCallLiftValueWithName cenv.g m vty v.LogicalName (exprForValRef m vref) + cenv.exprSplices.Add((liftExpr, m)) QP.mkHole(ConvType cenv env m vty, idx) + | Parent _ -> - ConvModuleValueApp cenv env m vref tyargs [] + + let witnessArgs = + if cenv.g.generateWitnesses && not env.isWitness then + ConstraintSolver.CodegenWitnessesForTyparInst cenv.tcVal cenv.g cenv.amap m vref.Typars tyargs + |> CommitOperationResult + else [] + + ConvModuleValueApp cenv env m vref tyargs witnessArgs [] and ConvUnionCaseRef cenv (ucref: UnionCaseRef) m = let ucgtypR = ConvTyconRef cenv ucref.TyconRef m @@ -881,9 +944,9 @@ and ConvDecisionTree cenv env tgs typR x = match discrim with | DecisionTreeTest.UnionCase (ucref, tyargs) -> let e1R = ConvLValueExpr cenv env e1 - let ucR = ConvUnionCaseRef cenv ucref m + let tcR, s = ConvUnionCaseRef cenv ucref m let tyargsR = ConvTypes cenv env m tyargs - QP.mkCond (QP.mkUnionCaseTagTest (ucR, tyargsR, e1R), ConvDecisionTree cenv env tgs typR dtree, acc) + QP.mkCond (QP.mkUnionCaseTagTest (tcR, s, tyargsR, e1R), ConvDecisionTree cenv env tgs typR dtree, acc) | DecisionTreeTest.Const (Const.Bool true) -> let e1R = ConvExpr cenv env e1 @@ -972,8 +1035,7 @@ and ConvILTypeRefUnadjusted cenv m (tr: ILTypeRef) = ConvILTypeRef cenv trefAdjusted and ConvILTypeRef cenv (tr: ILTypeRef) = - match cenv.quotationFormat with - | QuotationSerializationFormat.FSharp_40_Plus -> + if cenv.quotationFormat.SupportsDeserializeEx then let idx = match cenv.referencedTypeDefsTable.TryGetValue tr with | true, idx -> idx @@ -984,7 +1046,7 @@ and ConvILTypeRef cenv (tr: ILTypeRef) = idx QP.Idx idx - | QuotationSerializationFormat.FSharp_20_Plus -> + else let assemblyRef = match tr.Scope with | ILScopeRef.Local -> "." @@ -1060,7 +1122,7 @@ let ConvMethodBase cenv env (methName, v: Val) = | Some vspr when not v.IsExtensionMember -> let vref = mkLocalValRef v - let tps, argInfos, retTy, _ = GetTypeOfMemberInMemberForm cenv.g vref + let tps, cxs, argInfos, retTy, _ = GetTypeOfMemberInMemberForm cenv.g vref let numEnclTypeArgs = vref.MemberApparentEntity.TyparsNoRange.Length let argTys = argInfos |> List.concat |> List.map fst @@ -1068,45 +1130,51 @@ let ConvMethodBase cenv env (methName, v: Val) = // The signature types are w.r.t. to the formal context let envinner = BindFormalTypars env tps + let witnessArgTysR = ConvTypes cenv envinner m (GenWitnessTys cenv.g cxs) let methArgTypesR = ConvTypes cenv envinner m argTys let methRetTypeR = ConvReturnType cenv envinner m retTy let numGenericArgs = tps.Length-numEnclTypeArgs if isNewObj then - QP.MethodBaseData.Ctor - { ctorParent = parentTyconR - ctorArgTypes = methArgTypesR } + assert witnessArgTysR.IsEmpty + QP.MethodBaseData.Ctor + { ctorParent = parentTyconR + ctorArgTypes = methArgTypesR } else - QP.MethodBaseData.Method + QP.MethodBaseData.Method { methParent = parentTyconR - methArgTypes = methArgTypesR + methArgTypes = witnessArgTysR @ methArgTypesR methRetType = methRetTypeR methName = methName numGenericArgs=numGenericArgs } | _ when v.IsExtensionMember -> - let tps, argInfos, retTy, _ = GetTopValTypeInCompiledForm cenv.g v.ValReprInfo.Value v.Type v.Range + let tps, cxs, argInfos, retTy, _ = GetTopValTypeInCompiledForm cenv.g v.ValReprInfo.Value v.Type v.Range let argTys = argInfos |> List.concat |> List.map fst let envinner = BindFormalTypars env tps + let witnessArgTysR = ConvTypes cenv envinner m (GenWitnessTys cenv.g cxs) let methArgTypesR = ConvTypes cenv envinner m argTys let methRetTypeR = ConvReturnType cenv envinner m retTy let numGenericArgs = tps.Length QP.MethodBaseData.Method { methParent = parentTyconR - methArgTypes = methArgTypesR + methArgTypes = witnessArgTysR @ methArgTypesR methRetType = methRetTypeR methName = methName numGenericArgs=numGenericArgs } - | _ -> + | _ -> + let tps, cxs, _argInfos, _retTy, _ = GetTopValTypeInCompiledForm cenv.g v.ValReprInfo.Value v.Type v.Range + let envinner = BindFormalTypars env tps + let witnessArgTysR = ConvTypes cenv envinner m (GenWitnessTys cenv.g cxs) + let nWitnesses = witnessArgTysR.Length QP.MethodBaseData.ModuleDefn - { Name = methName - Module = parentTyconR - IsProperty = IsCompiledAsStaticProperty cenv.g v } - + ({ Name = methName + Module = parentTyconR + IsProperty = IsCompiledAsStaticProperty cenv.g v }, (if nWitnesses = 0 then None else Some (ExtraWitnessMethodName methName, nWitnesses))) // FSComp.SR.crefQuotationsCantContainLiteralByteArrays diff --git a/src/fsharp/QuotationTranslator.fsi b/src/fsharp/QuotationTranslator.fsi index 184f1d3da4e..da4db77b083 100755 --- a/src/fsharp/QuotationTranslator.fsi +++ b/src/fsharp/QuotationTranslator.fsi @@ -26,13 +26,17 @@ type IsReflectedDefinition = [] type QuotationSerializationFormat = - /// Indicates that type references are emitted as integer indexes into a supplied table - | FSharp_40_Plus - | FSharp_20_Plus + { + /// Indicates that witness parameters are recorded + SupportsWitnesses: bool + + /// Indicates that type references are emitted as integer indexes into a supplied table + SupportsDeserializeEx: bool + } [] type QuotationGenerationScope = - static member Create: TcGlobals * ImportMap * CcuThunk * IsReflectedDefinition -> QuotationGenerationScope + static member Create: TcGlobals * ImportMap * CcuThunk * ConstraintSolver.TcValF * IsReflectedDefinition -> QuotationGenerationScope member Close: unit -> ILTypeRef list * (TType * range) list * (Expr * range) list static member ComputeQuotationFormat : TcGlobals -> QuotationSerializationFormat diff --git a/src/fsharp/TastOps.fs b/src/fsharp/TastOps.fs index 6e05af04b66..b795496c564 100644 --- a/src/fsharp/TastOps.fs +++ b/src/fsharp/TastOps.fs @@ -905,6 +905,13 @@ let rec traitsAEquivAux erasureFlag g aenv (TTrait(tys1, nm, mf1, argtys, rty, _ returnTypesAEquivAux erasureFlag g aenv rty rty2 && List.lengthsEqAndForall2 (typeAEquivAux erasureFlag g aenv) argtys argtys2 +and traitKeysAEquivAux erasureFlag g aenv (TraitWitnessInfo(tys1, nm, mf1, argtys, rty)) (TraitWitnessInfo(tys2, nm2, mf2, argtys2, rty2)) = + mf1 = mf2 && + nm = nm2 && + ListSet.equals (typeAEquivAux erasureFlag g aenv) tys1 tys2 && + returnTypesAEquivAux erasureFlag g aenv rty rty2 && + List.lengthsEqAndForall2 (typeAEquivAux erasureFlag g aenv) argtys argtys2 + and returnTypesAEquivAux erasureFlag g aenv rty rty2 = match rty, rty2 with | None, None -> true @@ -1020,6 +1027,7 @@ and typeEquivAux erasureFlag g ty1 ty2 = typeAEquivAux erasureFlag g TypeEquivEn let typeAEquiv g aenv ty1 ty2 = typeAEquivAux EraseNone g aenv ty1 ty2 let typeEquiv g ty1 ty2 = typeEquivAux EraseNone g ty1 ty2 let traitsAEquiv g aenv t1 t2 = traitsAEquivAux EraseNone g aenv t1 t2 +let traitKeysAEquiv g aenv t1 t2 = traitKeysAEquivAux EraseNone g aenv t1 t2 let typarConstraintsAEquiv g aenv c1 c2 = typarConstraintsAEquivAux EraseNone g aenv c1 c2 let typarsAEquiv g aenv d1 d2 = typarsAEquivAux EraseNone g aenv d1 d2 let returnTypesAEquiv g aenv t1 t2 = returnTypesAEquivAux EraseNone g aenv t1 t2 @@ -1541,8 +1549,11 @@ let tryDestRefTupleTy g ty = if isRefTupleTy g ty then destRefTupleTy g ty else [ty] type UncurriedArgInfos = (TType * ArgReprInfo) list + type CurriedArgInfos = (TType * ArgReprInfo) list list +type TraitWitnessInfos = TraitWitnessInfo list + // A 'tau' type is one with its type parameters stripped off let GetTopTauTypeInFSharpForm g (curriedArgInfos: ArgReprInfo list list) tau m = let nArgInfos = curriedArgInfos.Length @@ -2246,8 +2257,25 @@ let checkMemberVal membInfo arity m = let checkMemberValRef (vref: ValRef) = checkMemberVal vref.MemberInfo vref.ValReprInfo vref.Range +// Get information about the as-ye-unsolved constraints for a set of typars +let GetTraitConstraintInfosOfTypars g (tps: Typars) = + let cxs = + tps |> List.collect (fun tp -> + tp.Constraints + |> List.choose (fun cx -> match cx with TyparConstraint.MayResolveMember(traitInfo, _) -> Some traitInfo | _ -> None) + |> List.sortBy (fun traitInfo -> traitInfo.MemberName, traitInfo.ArgumentTypes.Length)) + let cxs = cxs |> ListSet.setify (traitsAEquiv g TypeEquivEnv.Empty) + cxs + +// Get information about the runtime witnesses needed for a set of generalized typars +let GetTraitWitnessInfosOfTypars g parentTypars tps = + let tps = tps |> List.filter (fun tp -> not (parentTypars |> List.exists (typarEq tp))) + let cxs = GetTraitConstraintInfosOfTypars g tps + cxs |> List.map (fun cx -> cx.TraitKey) + let GetTopValTypeInCompiledForm g topValInfo ty m = let tps, paramArgInfos, rty, retInfo = GetTopValTypeInFSharpForm g topValInfo ty m + let witnessInfos = GetTraitWitnessInfosOfTypars g [] tps // TODO: parentTypars // Eliminate lone single unit arguments let paramArgInfos = match paramArgInfos, topValInfo.ArgInfos with @@ -2262,7 +2290,7 @@ let GetTopValTypeInCompiledForm g topValInfo ty m = | _ -> paramArgInfos let rty = if isUnitTy g rty then None else Some rty - (tps, paramArgInfos, rty, retInfo) + (tps, witnessInfos, paramArgInfos, rty, retInfo) // Pull apart the type for an F# value that represents an object model method // and see the "member" form for the type, i.e. @@ -2274,6 +2302,7 @@ let GetTopValTypeInCompiledForm g topValInfo ty m = // many arguments the method takes etc. let GetMemberTypeInMemberForm g memberFlags topValInfo ty m = let tps, paramArgInfos, rty, retInfo = GetMemberTypeInFSharpForm g memberFlags topValInfo ty m + let witnessInfos = GetTraitWitnessInfosOfTypars g [] tps // TODO: parentTypars // Eliminate lone single unit arguments let paramArgInfos = match paramArgInfos, topValInfo.ArgInfos with @@ -2288,7 +2317,7 @@ let GetMemberTypeInMemberForm g memberFlags topValInfo ty m = | _ -> paramArgInfos let rty = if isUnitTy g rty then None else Some rty - (tps, paramArgInfos, rty, retInfo) + (tps, witnessInfos, paramArgInfos, rty, retInfo) let GetTypeOfMemberInMemberForm g (vref: ValRef) = //assert (not vref.IsExtensionMember) @@ -2330,7 +2359,7 @@ let PartitionValRefTypars g (vref: ValRef) = PartitionValTypars g vref.Deref /// Get the arguments for an F# value that represents an object model method let ArgInfosOfMemberVal g (v: Val) = let membInfo, topValInfo = checkMemberVal v.MemberInfo v.ValReprInfo v.Range - let _, arginfos, _, _ = GetMemberTypeInMemberForm g membInfo.MemberFlags topValInfo v.Type v.Range + let _, _cxs, arginfos, _, _ = GetMemberTypeInMemberForm g membInfo.MemberFlags topValInfo v.Type v.Range arginfos let ArgInfosOfMember g (vref: ValRef) = @@ -2348,13 +2377,13 @@ let ReturnTypeOfPropertyVal g (v: Val) = let membInfo, topValInfo = checkMemberVal v.MemberInfo v.ValReprInfo v.Range match membInfo.MemberFlags.MemberKind with | MemberKind.PropertySet -> - let _, arginfos, _, _ = GetMemberTypeInMemberForm g membInfo.MemberFlags topValInfo v.Type v.Range + let _, _cxs, arginfos, _, _ = GetMemberTypeInMemberForm g membInfo.MemberFlags topValInfo v.Type v.Range if not arginfos.IsEmpty && not arginfos.Head.IsEmpty then arginfos.Head |> List.last |> fst else error(Error(FSComp.SR.tastValueDoesNotHaveSetterType(), v.Range)) | MemberKind.PropertyGet -> - let _, _, rty, _ = GetMemberTypeInMemberForm g membInfo.MemberFlags topValInfo v.Type v.Range + let _, _cxs, _, rty, _ = GetMemberTypeInMemberForm g membInfo.MemberFlags topValInfo v.Type v.Range GetFSharpViewOfReturnType g rty | _ -> error(InternalError("ReturnTypeOfPropertyVal", v.Range)) @@ -2367,7 +2396,7 @@ let ArgInfosOfPropertyVal g (v: Val) = | MemberKind.PropertyGet -> ArgInfosOfMemberVal g v |> List.concat | MemberKind.PropertySet -> - let _, arginfos, _, _ = GetMemberTypeInMemberForm g membInfo.MemberFlags topValInfo v.Type v.Range + let _, _cxs, arginfos, _, _ = GetMemberTypeInMemberForm g membInfo.MemberFlags topValInfo v.Type v.Range if not arginfos.IsEmpty && not arginfos.Head.IsEmpty then arginfos.Head |> List.frontAndBack |> fst else @@ -4787,8 +4816,12 @@ type StaticOptimizationAnswer = | No = -1y | Unknown = 0y -let decideStaticOptimizationConstraint g c = +let decideStaticOptimizationConstraint g c haveWitnesses = match c with + // When witnesses are available in generic code during codegen, "when ^T : ^T" resolves StaticOptimizationAnswer.Yes + // This doesn't apply to "when 'T : 'T" use for "FastGenericEqualityComparer" and others. + | TTyconEqualsTycon (a, b) when haveWitnesses && typeEquiv g a b && (match tryDestTyparTy g a with ValueSome tp -> tp.StaticReq = TyparStaticReq.HeadTypeStaticReq | _ -> false) -> + StaticOptimizationAnswer.Yes | TTyconEqualsTycon (a, b) -> // Both types must be nominal for a definite result let rec checkTypes a b = @@ -4824,17 +4857,17 @@ let decideStaticOptimizationConstraint g c = | ValueSome tcref1 -> if tcref1.IsStructOrEnumTycon then StaticOptimizationAnswer.Yes else StaticOptimizationAnswer.No | ValueNone -> StaticOptimizationAnswer.Unknown -let rec DecideStaticOptimizations g cs = +let rec DecideStaticOptimizations g cs haveWitnesses = match cs with | [] -> StaticOptimizationAnswer.Yes - | h :: t -> - let d = decideStaticOptimizationConstraint g h + | h::t -> + let d = decideStaticOptimizationConstraint g h haveWitnesses if d = StaticOptimizationAnswer.No then StaticOptimizationAnswer.No - elif d = StaticOptimizationAnswer.Yes then DecideStaticOptimizations g t + elif d = StaticOptimizationAnswer.Yes then DecideStaticOptimizations g t haveWitnesses else StaticOptimizationAnswer.Unknown let mkStaticOptimizationExpr g (cs, e1, e2, m) = - let d = DecideStaticOptimizations g cs in + let d = DecideStaticOptimizations g cs false if d = StaticOptimizationAnswer.No then e2 elif d = StaticOptimizationAnswer.Yes then e1 else Expr.StaticOptimization (cs, e1, e2, m) @@ -6798,6 +6831,25 @@ let mkCallNewDecimal (g: TcGlobals) m (e1, e2, e3, e4, e5) = mkApps g (typedExpr let mkCallNewFormat (g: TcGlobals) m aty bty cty dty ety e1 = mkApps g (typedExprForIntrinsic g m g.new_format_info, [[aty;bty;cty;dty;ety]], [ e1 ], m) +let tryMkCallBuiltInWitness (g: TcGlobals) traitInfo argExprs m = + let info = g.makeBuiltInWitnessInfo traitInfo + let vref = ValRefForIntrinsic info + match vref.TryDeref with + | ValueSome v -> + let f = exprForValRef m vref + mkApps g ((f, v.Type), [], [ mkRefTupledNoTypes g m argExprs ], m) |> Some + | ValueNone -> + None + +let tryMkCallCoreFunctionAsBuiltInWitness (g: TcGlobals) info tyargs argExprs m = + let vref = ValRefForIntrinsic info + match vref.TryDeref with + | ValueSome v -> + let f = exprForValRef m vref + mkApps g ((f, v.Type), [tyargs], argExprs, m) |> Some + | ValueNone -> + None + let TryEliminateDesugaredConstants g m c = match c with | Const.Decimal d -> @@ -7659,9 +7711,34 @@ let LinearizeTopMatch g parent = function //--------------------------------------------------------------------------- -// XmlDoc signatures +// Witnesses //--------------------------------------------------------------------------- +let GenWitnessArgTys (g: TcGlobals) (traitInfo: TraitWitnessInfo) = + let (TraitWitnessInfo(_tys, _nm, _memFlags, argtys, _rty)) = traitInfo + let argtys = if argtys.IsEmpty then [g.unit_ty] else argtys + let argtysl = List.map List.singleton argtys + argtysl + //match tys with + //| _ when not memFlags.IsInstance -> argtysl + //| [ty] -> [ty] :: argtysl + //| [_; _] -> [g.obj_ty] :: argtysl + //| _ -> failwith "unexpected empty type support for trait constraint" + +let GenWitnessTy (g: TcGlobals) (traitInfo: TraitWitnessInfo) = + let rty = match traitInfo.ReturnType with None -> g.unit_ty | Some ty -> ty + let argtysl = GenWitnessArgTys g traitInfo + mkMethodTy g argtysl rty + +let GenWitnessTys (g: TcGlobals) (cxs: TraitWitnessInfos) = + if g.generateWitnesses then + cxs |> List.map (GenWitnessTy g) + else + [] + +//--------------------------------------------------------------------------- +// XmlDoc signatures +//--------------------------------------------------------------------------- let commaEncs strs = String.concat "," strs let angleEnc str = "{" + str + "}" @@ -7742,9 +7819,9 @@ and tyargsEnc g (gtpsType, gtpsMethod) args = | [a] when (match (stripTyEqns g a) with TType_measure _ -> true | _ -> false) -> "" // float should appear as just "float" in the generated .XML xmldoc file | _ -> angleEnc (commaEncs (List.map (typeEnc g (gtpsType, gtpsMethod)) args)) -let XmlDocArgsEnc g (gtpsType, gtpsMethod) argTs = - if isNil argTs then "" - else "(" + String.concat "," (List.map (typeEnc g (gtpsType, gtpsMethod)) argTs) + ")" +let XmlDocArgsEnc g (gtpsType, gtpsMethod) argTys = + if isNil argTys then "" + else "(" + String.concat "," (List.map (typeEnc g (gtpsType, gtpsMethod)) argTys) + ")" let buildAccessPath (cp: CompilationPath option) = match cp with @@ -7754,8 +7831,8 @@ let buildAccessPath (cp: CompilationPath option) = | None -> "Extension Type" let prependPath path name = if path = "" then name else path + "." + name -let XmlDocSigOfVal g path (v: Val) = - let parentTypars, methTypars, argInfos, prefix, path, name = +let XmlDocSigOfVal g full path (v: Val) = + let parentTypars, methTypars, cxs, argInfos, rty, prefix, path, name = // CLEANUP: this is one of several code paths that treat module values and members // separately when really it would be cleaner to make sure GetTopValTypeInFSharpForm, GetMemberTypeInFSharpForm etc. @@ -7763,8 +7840,8 @@ let XmlDocSigOfVal g path (v: Val) = match v.MemberInfo with | Some membInfo when not v.IsExtensionMember -> - (* Methods, Properties etc. *) - let tps, argInfos, _, _ = GetMemberTypeInMemberForm g membInfo.MemberFlags (Option.get v.ValReprInfo) v.Type v.Range + // Methods, Properties etc. + let tps, cxs, argInfos, rty, _ = GetMemberTypeInMemberForm g membInfo.MemberFlags (Option.get v.ValReprInfo) v.Type v.Range let prefix, name = match membInfo.MemberFlags.MemberKind with | MemberKind.ClassConstructor @@ -7778,18 +7855,21 @@ let XmlDocSigOfVal g path (v: Val) = match PartitionValTypars g v with | Some(_, memberParentTypars, memberMethodTypars, _, _) -> memberParentTypars, memberMethodTypars | None -> [], tps - parentTypars, methTypars, argInfos, prefix, path, name + parentTypars, methTypars, cxs, argInfos, rty, prefix, path, name | _ -> // Regular F# values and extension members let w = arityOfVal v - let tps, argInfos, _, _ = GetTopValTypeInCompiledForm g w v.Type v.Range + let tps, cxs, argInfos, rty, _ = GetTopValTypeInCompiledForm g w v.Type v.Range let name = v.CompiledName let prefix = if w.NumCurriedArgs = 0 && isNil tps then "P:" else "M:" - [], tps, argInfos, prefix, path, name - let argTs = argInfos |> List.concat |> List.map fst - let args = XmlDocArgsEnc g (parentTypars, methTypars) argTs + [], tps, cxs, argInfos, rty, prefix, path, name + + let witnessArgTys = GenWitnessTys g cxs + let argTys = argInfos |> List.concat |> List.map fst + let argTys = witnessArgTys @ argTys @ (match rty with Some t when full -> [t] | _ -> []) + let args = XmlDocArgsEnc g (parentTypars, methTypars) argTys let arity = List.length methTypars in (* C# XML doc adds `` to *generic* member names *) let genArity = if arity=0 then "" else sprintf "``%d" arity prefix + prependPath path name + genArity + args @@ -8658,7 +8738,7 @@ let EvalLiteralExprOrAttribArg g x = let GetTypeOfIntrinsicMemberInCompiledForm g (vref: ValRef) = assert (not vref.IsExtensionMember) let membInfo, topValInfo = checkMemberValRef vref - let tps, argInfos, rty, retInfo = GetTypeOfMemberInMemberForm g vref + let tps, cxs, argInfos, rty, retInfo = GetTypeOfMemberInMemberForm g vref let argInfos = // Check if the thing is really an instance member compiled as a static member // If so, the object argument counts as a normal argument in the compiled form @@ -8670,7 +8750,7 @@ let GetTypeOfIntrinsicMemberInCompiledForm g (vref: ValRef) = argInfos | h :: _ -> h :: argInfos else argInfos - tps, argInfos, rty, retInfo + tps, cxs, argInfos, rty, retInfo //-------------------------------------------------------------------------- @@ -8893,5 +8973,3 @@ let isThreadOrContextStatic g attrs = let mkUnitDelayLambda (g: TcGlobals) m e = let uv, _ = mkCompGenLocal m "unitVar" g.unit_ty mkLambda m uv (e, tyOfExpr g e) - - diff --git a/src/fsharp/TastOps.fsi b/src/fsharp/TastOps.fsi index bf944a4f597..cef15271fab 100755 --- a/src/fsharp/TastOps.fsi +++ b/src/fsharp/TastOps.fsi @@ -723,6 +723,8 @@ type UncurriedArgInfos = (TType * ArgReprInfo) list type CurriedArgInfos = UncurriedArgInfos list +type TraitWitnessInfos = TraitWitnessInfo list + val destTopForallTy : TcGlobals -> ValReprInfo -> TType -> Typars * TType val GetTopTauTypeInFSharpForm : TcGlobals -> ArgReprInfo list list -> TType -> range -> CurriedArgInfos * TType @@ -733,7 +735,7 @@ val IsCompiledAsStaticProperty : TcGlobals -> Val -> bool val IsCompiledAsStaticPropertyWithField : TcGlobals -> Val -> bool -val GetTopValTypeInCompiledForm : TcGlobals -> ValReprInfo -> TType -> range -> Typars * CurriedArgInfos * TType option * ArgReprInfo +val GetTopValTypeInCompiledForm : TcGlobals -> ValReprInfo -> TType -> range -> Typars * TraitWitnessInfos * CurriedArgInfos * TType option * ArgReprInfo val GetFSharpViewOfReturnType : TcGlobals -> TType option -> TType @@ -829,6 +831,10 @@ val traitsAEquivAux : Erasure -> TcGlobals -> TypeEquivEnv -> TraitCon val traitsAEquiv : TcGlobals -> TypeEquivEnv -> TraitConstraintInfo -> TraitConstraintInfo -> bool +val traitKeysAEquivAux : Erasure -> TcGlobals -> TypeEquivEnv -> TraitWitnessInfo -> TraitWitnessInfo -> bool + +val traitKeysAEquiv : TcGlobals -> TypeEquivEnv -> TraitWitnessInfo -> TraitWitnessInfo -> bool + val typarConstraintsAEquivAux : Erasure -> TcGlobals -> TypeEquivEnv -> TyparConstraint -> TyparConstraint -> bool val typarConstraintsAEquiv : TcGlobals -> TypeEquivEnv -> TyparConstraint -> TyparConstraint -> bool @@ -884,11 +890,11 @@ val normalizeMeasure : TcGlobals -> Measure -> Measure val GetTypeOfMemberInFSharpForm : TcGlobals -> ValRef -> Typars * CurriedArgInfos * TType * ArgReprInfo -val GetTypeOfMemberInMemberForm : TcGlobals -> ValRef -> Typars * CurriedArgInfos * TType option * ArgReprInfo +val GetTypeOfMemberInMemberForm : TcGlobals -> ValRef -> Typars * TraitWitnessInfos * CurriedArgInfos * TType option * ArgReprInfo -val GetTypeOfIntrinsicMemberInCompiledForm : TcGlobals -> ValRef -> Typars * CurriedArgInfos * TType option * ArgReprInfo +val GetTypeOfIntrinsicMemberInCompiledForm : TcGlobals -> ValRef -> Typars * TraitWitnessInfos * CurriedArgInfos * TType option * ArgReprInfo -val GetMemberTypeInMemberForm : TcGlobals -> MemberFlags -> ValReprInfo -> TType -> range -> Typars * CurriedArgInfos * TType option * ArgReprInfo +val GetMemberTypeInMemberForm : TcGlobals -> MemberFlags -> ValReprInfo -> TType -> range -> Typars * TraitWitnessInfos * CurriedArgInfos * TType option * ArgReprInfo /// Returns (parentTypars,memberParentTypars,memberMethodTypars,memberToParentInst,tinst) val PartitionValTyparsForApparentEnclosingType : TcGlobals -> Val -> (Typars * Typars * Typars * TyparInst * TType list) option @@ -1969,6 +1975,12 @@ val mkStaticCall_String_Concat4 : TcGlobals -> range -> Expr -> Expr -> Expr -> val mkStaticCall_String_Concat_Array : TcGlobals -> range -> Expr -> Expr +/// Use a witness in BuiltInWitnesses +val tryMkCallBuiltInWitness : TcGlobals -> TraitConstraintInfo -> Expr list -> range -> Expr option + +/// Use an operator as a witness +val tryMkCallCoreFunctionAsBuiltInWitness : TcGlobals -> IntrinsicValRef -> TType list -> Expr list -> range -> Expr option + //------------------------------------------------------------------------- // operations primarily associated with the optimization to fix // up loops to generate .NET code that does not include array bound checks @@ -2140,7 +2152,7 @@ val buildAccessPath : CompilationPath option -> string val XmlDocArgsEnc : TcGlobals -> Typars * Typars -> TType list -> string -val XmlDocSigOfVal : TcGlobals -> string -> Val -> string +val XmlDocSigOfVal : TcGlobals -> full: bool -> string -> Val -> string val XmlDocSigOfUnionCase : (string list -> string) @@ -2163,7 +2175,7 @@ type StaticOptimizationAnswer = | No = -1y | Unknown = 0y -val DecideStaticOptimizations : TcGlobals -> StaticOptimization list -> StaticOptimizationAnswer +val DecideStaticOptimizations : TcGlobals -> StaticOptimization list -> haveWitnesses: bool -> StaticOptimizationAnswer val mkStaticOptimizationExpr : TcGlobals -> StaticOptimization list * Expr * Expr * range -> Expr @@ -2293,3 +2305,13 @@ val isThreadOrContextStatic: TcGlobals -> Attrib list -> bool val mkUnitDelayLambda: TcGlobals -> range -> Expr -> Expr +val GenWitnessArgTys: TcGlobals -> TraitWitnessInfo -> TType list list + +val GenWitnessTys: TcGlobals -> TraitWitnessInfos -> TType list + +val GenWitnessTy: TcGlobals -> TraitWitnessInfo -> TType + +val GetTraitConstraintInfosOfTypars: TcGlobals -> Typars -> TraitConstraintInfo list + +val GetTraitWitnessInfosOfTypars: TcGlobals -> parentTypars: Typars -> typars: Typars -> TraitWitnessInfos + diff --git a/src/fsharp/TcGlobals.fs b/src/fsharp/TcGlobals.fs index aa9a052ed63..d59ea515692 100755 --- a/src/fsharp/TcGlobals.fs +++ b/src/fsharp/TcGlobals.fs @@ -355,7 +355,7 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d // A table of all intrinsics that the compiler cares about let v_knownIntrinsics = Dictionary<(string*string), ValRef>(HashIdentity.Structural) - let makeIntrinsicValRef (enclosingEntity, logicalName, memberParentName, compiledNameOpt, typars, (argtys, rty)) = + let makeIntrinsicValRefGeneral isKnown (enclosingEntity, logicalName, memberParentName, compiledNameOpt, typars, (argtys, rty)) = let ty = mkForallTyIfNeeded typars (mkIteratedFunTy (List.map mkSmallRefTupledTy argtys) rty) let isMember = Option.isSome memberParentName let argCount = if isMember then List.sum (List.map List.length argtys) else 0 @@ -363,9 +363,12 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d let key = ValLinkageFullKey({ MemberParentMangledName=memberParentName; MemberIsOverride=false; LogicalName=logicalName; TotalArgCount= argCount }, linkageType) let vref = IntrinsicValRef(enclosingEntity, logicalName, isMember, ty, key) let compiledName = defaultArg compiledNameOpt logicalName - v_knownIntrinsics.Add((enclosingEntity.LastItemMangledName, compiledName), ValRefForIntrinsic vref) + if isKnown then + v_knownIntrinsics.Add((enclosingEntity.LastItemMangledName, compiledName), ValRefForIntrinsic vref) vref + let makeIntrinsicValRef info = makeIntrinsicValRefGeneral true info + let makeOtherIntrinsicValRef info = makeIntrinsicValRefGeneral false info let v_IComparer_ty = mkSysNonGenericTy sysCollections "IComparer" let v_IEqualityComparer_ty = mkSysNonGenericTy sysCollections "IEqualityComparer" @@ -708,6 +711,7 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d let v_new_decimal_info = makeIntrinsicValRef(fslib_MFIntrinsicFunctions_nleref, "MakeDecimal" , None , None , [], ([[v_int_ty]; [v_int_ty]; [v_int_ty]; [v_bool_ty]; [v_byte_ty]], v_decimal_ty)) let v_deserialize_quoted_FSharp_20_plus_info = makeIntrinsicValRef(fslib_MFQuotations_nleref, "Deserialize" , Some "Expr" , None , [], ([[v_system_Type_ty ;mkListTy v_system_Type_ty ;mkListTy mkRawQuotedExprTy ; mkArrayType 1 v_byte_ty]], mkRawQuotedExprTy )) let v_deserialize_quoted_FSharp_40_plus_info = makeIntrinsicValRef(fslib_MFQuotations_nleref, "Deserialize40" , Some "Expr" , None , [], ([[v_system_Type_ty ;mkArrayType 1 v_system_Type_ty; mkArrayType 1 v_system_Type_ty; mkArrayType 1 mkRawQuotedExprTy; mkArrayType 1 v_byte_ty]], mkRawQuotedExprTy )) + let v_call_with_witnesses_info = makeIntrinsicValRef(fslib_MFQuotations_nleref, "CallWithWitnesses" , Some "Expr" , None , [], ([[v_system_Reflection_MethodInfo_ty; v_system_Reflection_MethodInfo_ty; mkListTy mkRawQuotedExprTy; mkListTy mkRawQuotedExprTy]], mkRawQuotedExprTy)) let v_cast_quotation_info = makeIntrinsicValRef(fslib_MFQuotations_nleref, "Cast" , Some "Expr" , None , [vara], ([[mkRawQuotedExprTy]], mkQuotedExprTy varaTy)) let v_lift_value_info = makeIntrinsicValRef(fslib_MFQuotations_nleref, "Value" , Some "Expr" , None , [vara], ([[varaTy]], mkRawQuotedExprTy)) let v_lift_value_with_name_info = makeIntrinsicValRef(fslib_MFQuotations_nleref, "ValueWithName" , Some "Expr" , None , [vara], ([[varaTy; v_string_ty]], mkRawQuotedExprTy)) @@ -1407,6 +1411,7 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d member __.deserialize_quoted_FSharp_20_plus_info = v_deserialize_quoted_FSharp_20_plus_info member __.deserialize_quoted_FSharp_40_plus_info = v_deserialize_quoted_FSharp_40_plus_info + member __.call_with_witnesses_info = v_call_with_witnesses_info member __.cast_quotation_info = v_cast_quotation_info member __.lift_value_info = v_lift_value_info member __.lift_value_with_name_info = v_lift_value_with_name_info @@ -1442,9 +1447,14 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d // Note that the suppression checks for the precise name of the type // so the lowercase versions are visible member __.suppressed_types = v_suppressed_types + /// Are we assuming all code gen is for F# interactive, with no static linking member __.isInteractive=isInteractive + /// Indicates if we are generating witness arguments for SRTP constraints. Only done if the FSharp.Core + /// supports witness arguments. + member g.generateWitnesses = compilingFslib || (ValRefForIntrinsic g.call_with_witnesses_info).TryDeref.IsSome + member __.FindSysTyconRef path nm = findSysTyconRef path nm member __.TryFindSysTyconRef path nm = tryFindSysTyconRef path nm member __.FindSysILTypeRef nm = findSysILTypeRef nm @@ -1481,6 +1491,59 @@ type public TcGlobals(compilingFslib: bool, ilg:ILGlobals, fslibCcu: CcuThunk, d member __.eraseClassUnionDef = EraseUnions.mkClassUnionDef (addMethodGeneratedAttrs, addPropertyGeneratedAttrs, addPropertyNeverAttrs, addFieldGeneratedAttrs, addFieldNeverAttrs, mkDebuggerTypeProxyAttribute) ilg + /// Find an FSharp.Core BuiltInWitness that corresponds to a trait witness + member g.makeBuiltInWitnessInfo (t: TraitConstraintInfo) = + makeOtherIntrinsicValRef (fslib_MFLanguagePrimitives_nleref, t.MemberName, Some "BuiltInWitnesses", None, [], ([t.ArgumentTypes], defaultArg t.ReturnType g.unit_ty)) + + /// Find an FSharp.Core operator that corresponds to a trait witness + member g.tryMakeOperatorAsBuiltInWitnessInfo isStringTy isArrayTy (t: TraitConstraintInfo) argExprs = + + match t.MemberName, t.ArgumentTypes, t.ReturnType, argExprs with + | "get_Sign", [aty], _, (objExpr :: _) -> + // Call Operators.sign + let info = makeOtherIntrinsicValRef (fslib_MFOperators_nleref, "sign", None, Some "Sign", [vara], ([[varaTy]], v_int32_ty)) + let tyargs = [aty] + Some (info, tyargs, [objExpr]) + | "Sqrt", [aty], Some bty, [_] -> + // Call Operators.sqrt + let info = makeOtherIntrinsicValRef (fslib_MFOperators_nleref, "sqrt", None, Some "Sqrt", [vara; varb], ([[varaTy]], varbTy)) + let tyargs = [aty; bty] + Some (info, tyargs, argExprs) + | "Pow", [aty;bty], _, [_;_] -> + // Call Operators.(**) + let info = makeOtherIntrinsicValRef (fslib_MFOperators_nleref, "op_Exponentiation", None, None, [vara; varb], ([[varaTy]; [varbTy]], varaTy)) + let tyargs = [aty;bty] + Some (info, tyargs, argExprs) + | "Atan2", [aty;_], Some bty, [_;_] -> + // Call Operators.atan2 + let info = makeOtherIntrinsicValRef (fslib_MFOperators_nleref, "atan2", None, Some "Atan2", [vara; varb], ([[varaTy]; [varaTy]], varbTy)) + let tyargs = [aty;bty] + Some (info, tyargs, argExprs) + | "get_Zero", _, Some aty, [_] -> + // Call LanguagePrimitives.GenericZero + let info = makeOtherIntrinsicValRef (fslib_MFLanguagePrimitives_nleref, "GenericZero", None, None, [vara], ([], varaTy)) + let tyargs = [aty] + Some (info, tyargs, []) + | "get_One", _, Some aty, [_] -> + // Call LanguagePrimitives.GenericOne + let info = makeOtherIntrinsicValRef (fslib_MFLanguagePrimitives_nleref, "GenericOne", None, None, [vara], ([], varaTy)) + let tyargs = [aty] + Some (info, tyargs, []) + | ("Abs" | "Sin" | "Cos" | "Tan" | "Sinh" | "Cosh" | "Tanh" | "Atan" | "Acos" | "Asin" | "Exp" | "Ceiling" | "Floor" | "Round" | "Truncate" | "Log10"| "Log"), [aty], _, [_] -> + // Call corresponding Operators.* + let nm = t.MemberName + let lower = if nm = "Ceiling" then "ceil" else nm.ToLowerInvariant() + let info = makeOtherIntrinsicValRef (fslib_MFOperators_nleref, lower, None, Some nm, [vara], ([[varaTy]], varaTy)) + let tyargs = [aty] + Some (info, tyargs, argExprs) + | "get_Item", [arrTy; _], Some rty, [_; _] when isArrayTy g arrTy -> + Some (g.array_get_info, [rty], argExprs) + | "set_Item", [arrTy; _; ety], _, [_; _; _] when isArrayTy g arrTy -> + Some (g.array_set_info, [ety], argExprs) + | "get_Item", [sty; _; _], _, [_; _] when isStringTy g sty -> + Some (g.getstring_info, [], argExprs) + | _ -> + None #if DEBUG // This global is only used during debug output diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 3add36732fa..febc9cf8d3e 100644 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -4361,8 +4361,8 @@ and TcPseudoMemberSpec cenv newOk env synTypes tpenv memSpfn m = | [ValSpecResult(_, _, id, _, _, memberConstraintTy, partialValReprInfo, _)] -> let memberConstraintTypars, _ = tryDestForallTy cenv.g memberConstraintTy let topValInfo = TranslatePartialArity memberConstraintTypars partialValReprInfo - let _, curriedArgInfos, returnTy, _ = GetTopValTypeInCompiledForm cenv.g topValInfo memberConstraintTy m - //if curriedArgInfos.Length > 1 then error(Error(FSComp.SR.tcInvalidConstraint(), m)) + let _, _cxs, curriedArgInfos, returnTy, _ = GetTopValTypeInCompiledForm cenv.g topValInfo memberConstraintTy m + //if curriedArgInfos.Length > 1 then error(Error(FSComp.SR.tcInvalidConstraint(), m)) let argTys = List.concat curriedArgInfos let argTys = List.map fst argTys let logicalCompiledName = ComputeLogicalName id memberFlags @@ -12830,7 +12830,7 @@ module IncrClassChecking = InVar isCtorArg | topValInfo -> //dprintfn "Representing %s as a method %s" v.LogicalName name - let tps, argInfos, _, _ = GetTopValTypeInCompiledForm g topValInfo v.Type v.Range + let tps, _cxs, argInfos, _, _ = GetTopValTypeInCompiledForm g topValInfo v.Type v.Range let valSynInfo = SynValInfo(argInfos |> List.mapSquared (fun (_, argInfo) -> SynArgInfo([], false, argInfo.Name)), SynInfo.unnamedRetVal) let memberFlags = (if isStatic then StaticMemberFlags else NonVirtualMemberFlags) MemberKind.Member @@ -12848,6 +12848,7 @@ module IncrClassChecking = let (ValReprInfo(tpNames, args, ret)) = topValInfo let topValInfo = ValReprInfo(tpNames, ValReprInfo.selfMetadata :: args, ret) tauTy, topValInfo + // Add the enclosing type parameters on to the function let topValInfo = let (ValReprInfo(tpNames, args, ret)) = topValInfo @@ -15831,7 +15832,7 @@ module EstablishTypeDefinitionCores = noAbstractClassAttributeCheck() noFieldsCheck userFields let ty', _ = TcTypeAndRecover cenv NoNewTypars CheckCxs ItemOccurence.UseInType envinner tpenv ty - let _, curriedArgInfos, returnTy, _ = GetTopValTypeInCompiledForm g (arity |> TranslateTopValSynInfo m (TcAttributes cenv envinner) |> TranslatePartialArity []) ty' m + let _, _cxs, curriedArgInfos, returnTy, _ = GetTopValTypeInCompiledForm cenv.g (arity |> TranslateTopValSynInfo m (TcAttributes cenv envinner) |> TranslatePartialArity []) ty' m if curriedArgInfos.Length < 1 then error(Error(FSComp.SR.tcInvalidDelegateSpecification(), m)) if curriedArgInfos.Length > 1 then error(Error(FSComp.SR.tcDelegatesCannotBeCurried(), m)) let ttps = thisTyconRef.Typars m @@ -17639,10 +17640,10 @@ let TypeCheckOneImplFile try let reportErrors = not (checkForErrors()) - + let tcVal = LightweightTcValForUsingInBuildMethodCall g PostTypeCheckSemanticChecks.CheckTopImpl (g, cenv.amap, reportErrors, cenv.infoReader, - env.eInternalsVisibleCompPaths, cenv.topCcu, envAtEnd.DisplayEnv, + env.eInternalsVisibleCompPaths, cenv.topCcu, tcVal, envAtEnd.DisplayEnv, implFileExprAfterSig, extraAttribs, isLastCompiland, isInternalTestSpanStackReferring) diff --git a/src/fsharp/fsc.fs b/src/fsharp/fsc.fs index 568773a361c..a2c7b814134 100644 --- a/src/fsharp/fsc.fs +++ b/src/fsharp/fsc.fs @@ -336,7 +336,7 @@ module XmlDocWriter = let computeXmlDocSigs (tcGlobals, generatedCcu: CcuThunk) = (* the xmlDocSigOf* functions encode type into string to be used in "id" *) let g = tcGlobals - let doValSig ptext (v: Val) = if (hasDoc v.XmlDoc) then v.XmlDocSig <- XmlDocSigOfVal g ptext v + let doValSig ptext (v: Val) = if hasDoc v.XmlDoc then v.XmlDocSig <- XmlDocSigOfVal g false ptext v let doTyconSig ptext (tc: Tycon) = if (hasDoc tc.XmlDoc) then tc.XmlDocSig <- XmlDocSigOfTycon [ptext; tc.CompiledName] for vref in tc.MembersOfFSharpTyconSorted do @@ -887,10 +887,10 @@ module MainModuleBuilder = |> List.map (fun (referencedTypeDefs, reflectedDefinitionBytes) -> let reflectedDefinitionResourceName = QuotationPickler.SerializedReflectedDefinitionsResourceNameBase+"-"+assemblyName+"-"+string(newUnique())+"-"+string(hash reflectedDefinitionBytes) let reflectedDefinitionAttrs = - match QuotationTranslator.QuotationGenerationScope.ComputeQuotationFormat tcGlobals with - | QuotationTranslator.QuotationSerializationFormat.FSharp_40_Plus -> + let qf = QuotationTranslator.QuotationGenerationScope.ComputeQuotationFormat tcGlobals + if qf.SupportsDeserializeEx then [ mkCompilationMappingAttrForQuotationResource tcGlobals (reflectedDefinitionResourceName, referencedTypeDefs) ] - | QuotationTranslator.QuotationSerializationFormat.FSharp_20_Plus -> + else [ ] let reflectedDefinitionResource = { Name=reflectedDefinitionResourceName diff --git a/src/fsharp/infos.fs b/src/fsharp/infos.fs index dd6f8b0e3f3..13b64cca44e 100755 --- a/src/fsharp/infos.fs +++ b/src/fsharp/infos.fs @@ -436,7 +436,7 @@ let MakeSlotSig (nm, ty, ctps, mtps, paraml, retTy) = copySlotSig (TSlotSig(nm, /// - the return type of the method /// - the actual type arguments of the enclosing type. let private AnalyzeTypeOfMemberVal isCSharpExt g (ty, vref: ValRef) = - let memberAllTypars, _, retTy, _ = GetTypeOfMemberInMemberForm g vref + let memberAllTypars, _cxs, _, retTy, _ = GetTypeOfMemberInMemberForm g vref if isCSharpExt || vref.IsExtensionMember then [], memberAllTypars, retTy, [] else @@ -446,13 +446,13 @@ let private AnalyzeTypeOfMemberVal isCSharpExt g (ty, vref: ValRef) = /// Get the object type for a member value which is an extension method (C#-style or F#-style) let private GetObjTypeOfInstanceExtensionMethod g (vref: ValRef) = - let _, curriedArgInfos, _, _ = GetTopValTypeInCompiledForm g vref.ValReprInfo.Value vref.Type vref.Range + let _, _cxs, curriedArgInfos, _, _ = GetTopValTypeInCompiledForm g vref.ValReprInfo.Value vref.Type vref.Range curriedArgInfos.Head.Head |> fst -/// Get the object type for a member value which is a C#-style extension method -let private GetArgInfosOfMember isCSharpExt g (vref: ValRef) = +/// Get the object type for a member value, which might be a C#-style extension method +let private GetArgInfosOfMember isCSharpExt g (vref:ValRef) = if isCSharpExt then - let _, curriedArgInfos, _, _ = GetTopValTypeInCompiledForm g vref.ValReprInfo.Value vref.Type vref.Range + let _, _cxs, curriedArgInfos, _, _ = GetTopValTypeInCompiledForm g vref.ValReprInfo.Value vref.Type vref.Range [ curriedArgInfos.Head.Tail ] else ArgInfosOfMember g vref @@ -1481,7 +1481,8 @@ type MethInfo = | ValInRecScope false -> error(Error((FSComp.SR.InvalidRecursiveReferenceToAbstractSlot()), m)) | _ -> () - let allTyparsFromMethod, _, retTy, _ = GetTypeOfMemberInMemberForm g vref + // TODO: consider witnesses w.r.t. slot sigs? + let allTyparsFromMethod, _cxs, _, retTy, _ = GetTypeOfMemberInMemberForm g vref // A slot signature is w.r.t. the type variables of the type it is associated with. // So we have to rename from the member type variables to the type variables of the type. let formalEnclosingTypars = x.ApparentEnclosingTyconRef.Typars m diff --git a/src/fsharp/symbols/SymbolHelpers.fs b/src/fsharp/symbols/SymbolHelpers.fs index 0547f759df2..df2bf246d05 100644 --- a/src/fsharp/symbols/SymbolHelpers.fs +++ b/src/fsharp/symbols/SymbolHelpers.fs @@ -510,7 +510,7 @@ module internal SymbolHelpers = ap + sep + vref.TopValDeclaringEntity.CompiledName else ap - v.XmlDocSig <- XmlDocSigOfVal g path v + v.XmlDocSig <- XmlDocSigOfVal g false path v Some (ccuFileName, v.XmlDocSig) let GetXmlDocSigOfRecdFieldInfo (rfinfo: RecdFieldInfo) = @@ -563,7 +563,7 @@ module internal SymbolHelpers = let ccuFileName = vref.nlr.Ccu.FileName let v = vref.Deref if v.XmlDocSig = "" && v.HasDeclaringEntity then - v.XmlDocSig <- XmlDocSigOfVal g vref.TopValDeclaringEntity.CompiledRepresentationForNamedType.Name v + v.XmlDocSig <- XmlDocSigOfVal g false vref.TopValDeclaringEntity.CompiledRepresentationForNamedType.Name v Some (ccuFileName, v.XmlDocSig) else None diff --git a/src/fsharp/tast.fs b/src/fsharp/tast.fs index 33fffda0a26..2496694c502 100644 --- a/src/fsharp/tast.fs +++ b/src/fsharp/tast.fs @@ -2371,6 +2371,15 @@ and override x.ToString() = sprintf "%+A" x +and TraitWitnessInfo = + | TraitWitnessInfo of TTypes * string * MemberFlags * TTypes * TType option + + /// Get the member name associated with the member constraint. + member x.MemberName = (let (TraitWitnessInfo(_, b, _, _, _)) = x in b) + + /// Get the return type recorded in the member constraint. + member x.ReturnType = (let (TraitWitnessInfo(_, _, _, _, ty)) = x in ty) + /// The specification of a member constraint that must be solved and [] @@ -2382,9 +2391,19 @@ and /// to store the inferred solution of the constraint. | TTrait of TTypes * string * MemberFlags * TTypes * TType option * TraitConstraintSln option ref + /// Get the key associated with the member constraint. + member x.TraitKey = (let (TTrait(a, b, c, d, e, _)) = x in TraitWitnessInfo(a, b, c, d, e)) + /// Get the member name associated with the member constraint. member x.MemberName = (let (TTrait(_, nm, _, _, _, _)) = x in nm) + /// Get the member flags associated with the member constraint. + member x.MemberFlags = (let (TTrait(_, _, flags, _, _, _)) = x in flags) + + /// Get the argument types recorded in the member constraint. This includes the object instance type for + /// instance members. + member x.ArgumentTypes = (let (TTrait(_, _, _, argtys, _, _)) = x in argtys) + /// Get the return type recorded in the member constraint. member x.ReturnType = (let (TTrait(_, _, _, _, ty, _)) = x in ty) diff --git a/src/scripts/scriptlib.fsx b/src/scripts/scriptlib.fsx index f5f9276c492..ce9ac2e3cc8 100644 --- a/src/scripts/scriptlib.fsx +++ b/src/scripts/scriptlib.fsx @@ -108,12 +108,8 @@ module Scripting = processInfo.UseShellExecute <- false processInfo.WorkingDirectory <- workDir -#if !NET46 - ignore envs // work out what to do about this -#else envs |> Map.iter (fun k v -> processInfo.EnvironmentVariables.[k] <- v) -#endif let p = new Process() p.EnableRaisingEvents <- true diff --git a/tests/fsharp/core/quotes/test.fsx b/tests/fsharp/core/quotes/test.fsx index 289988569de..85393ff87a0 100644 --- a/tests/fsharp/core/quotes/test.fsx +++ b/tests/fsharp/core/quotes/test.fsx @@ -460,8 +460,7 @@ module TypedTest = begin test "check AddressOf rebuild" (try rebuild <@ let mutable a = 10 in increment(&a) @> |> ignore; true with _ -> false) test "check AddressOf argument" (<@ let mutable a = 10 in increment(&a) @> |> function Let(_, _, Call(None, _, [AddressOf(_)])) -> true | _ -> false) test "check AddressOf type" (<@ let mutable a = 10 in increment(&a) @> |> function Let(_, _, Call(None, _, [AddressOf(_) as e])) -> (try e.Type = typeof.MakeByRefType() with _ -> false) | _ -> false) - - + // Test basic expression splicing let f8383 (x:int) (y:string) = 0 let test2 = @@ -553,6 +552,7 @@ module TypedTest = begin end #endif + end (* @@ -3177,6 +3177,476 @@ module TestMatchBang = testSimpleMatchBang() +module WitnessTests = + open FSharp.Data.UnitSystems.SI.UnitSymbols + + test "check CallWithWitness" + (<@ 1 + 1 @> + |> function + | CallWithWitnesses(None, minfo1, minfo2, witnessArgs, args) -> + minfo1.Name = "op_Addition" && + minfo1.GetParameters().Length = 2 && + minfo2.Name = "op_AdditionWithWitnesses" && + minfo2.GetParameters().Length = 3 && + (printfn "checking witnessArgs.Length = %d... args.Length"; true) && + witnessArgs.Length = 1 && + (printfn "checking args.Length = %d... args.Length"; true) && + args.Length = 2 && + (printfn "checking witnessArgs is a Lambda..."; true) && + (match witnessArgs with [ Lambda _ ] -> true | _ -> false) && + (printfn "checking witnessArg is the expected call..."; true) && + (match witnessArgs with [ Lambda (v1A, Lambda (v2A, Call(None, m, [ Patterns.Var v1B; Patterns.Var v2B]))) ] when m.Name = "op_Addition" && v1A = v1B && v2A = v2B -> true | _ -> false) + (printfn "checking witnessArg is not a CalWithWitnesses..."; true) && + (match witnessArgs with [ Lambda (v1A, Lambda (v2A, CallWithWitnesses _)) ] -> false | _ -> true) && + (printfn "checking args..."; true) && + (match args with [ Int32 _; Int32 _ ] -> true | _ -> false) + | _ -> false) + + test "check CallWithWitness (DateTime + TimeSpan)" + (<@ System.DateTime.Now + System.TimeSpan.Zero @> + |> function + | CallWithWitnesses(None, minfo1, minfo2, witnessArgs, args) -> + minfo1.Name = "op_Addition" && + (printfn "checking minfo1.GetParameters().Length..."; true) && + minfo1.GetParameters().Length = 2 && + minfo2.Name = "op_AdditionWithWitnesses" && + (printfn "checking minfo2.GetParameters().Length..."; true) && + minfo2.GetParameters().Length = 3 && + (printfn "checking witnessArgs.Length..."; true) && + witnessArgs.Length = 1 && + (printfn "checking witnessArg is the expected call, witnessArgs = %A" witnessArgs; true) && + (match witnessArgs with + | [ Lambda (v1A, Lambda (v2A, Call(None, m, [Patterns.Var v1B; Patterns.Var v2B]))) ] + when m.Name = "op_Addition" + && m.GetParameters().[0].ParameterType.Name = "DateTime" + && m.GetParameters().[1].ParameterType.Name = "TimeSpan" + && v1A = v1B + && v2A = v2B -> true + | _ -> false) + (printfn "checking witnessArg is not a CallWithWitnesses, witnessArgs = %A" witnessArgs; true) && + (match witnessArgs with [ Lambda (v1A, Lambda (v2A, CallWithWitnesses args)) ] -> printfn "unexpected! %A" args; false | _ -> true) && + args.Length = 2 && + (printfn "checking args..."; true) && + (match args with [ _; _ ] -> true | _ -> false) && + (match witnessArgs with [ Lambda _ ] -> true | _ -> false) + | CallWithWitnesses _ -> + printfn "no object" + false + | _ -> + printfn "incorrect node" + false) + + test "check Call (DateTime + TimeSpan)" + (<@ System.DateTime.Now + System.TimeSpan.Zero @> + |> function + | Call(None, minfo1, args) -> + minfo1.Name = "op_Addition" && + (printfn "checking minfo1.GetParameters().Length..."; true) && + minfo1.GetParameters().Length = 2 && + //minfo2.GetParameters().[0].Name = "op_Addition" && + args.Length = 2 && + (match args with [ _; _ ] -> true | _ -> false) + | _ -> false) + + type C() = + static member inline StaticAdd (x, y) = x + y + member inline __.InstanceAdd (x, y) = x + y + + test "check CallWithWitness (DateTime + TimeSpan) using static member" + (<@ C.StaticAdd(System.DateTime.Now, System.TimeSpan.Zero) @> + |> function + | CallWithWitnesses(None, minfo1, minfo2, witnessArgs, args) -> + minfo1.IsStatic && + minfo1.Name = "StaticAdd" && + (printfn "checking minfo1.GetParameters().Length..."; true) && + minfo1.GetParameters().Length = 2 && + minfo2.IsStatic && + minfo2.Name = "StaticAddWithWitnesses" && + (printfn "checking minfo2.GetParameters().Length = %d..." (minfo2.GetParameters().Length); true) && + minfo2.GetParameters().Length = 3 && + (printfn "checking witnessArgs.Length..."; true) && + witnessArgs.Length = 1 && + (printfn "checking args.Length..."; true) && + args.Length = 2 && + (printfn "witnessArgs..."; true) && + (match witnessArgs with [ Lambda _ ] -> true | _ -> false) && + (printfn "args..."; true) && + (match args with [ _; _ ] -> true | _ -> false) + | CallWithWitnesses(None, minfo1, minfo2, witnessArgs, args) -> + printfn "no object..." + false + | _ -> false) + + test "check CallWithWitness (DateTime + TimeSpan) using instance member" + (<@ C().InstanceAdd(System.DateTime.Now, System.TimeSpan.Zero) @> + |> function + | CallWithWitnesses(Some _obj, minfo1, minfo2, witnessArgs, args) -> + not minfo1.IsStatic && + minfo1.Name = "InstanceAdd" && + (printfn "checking minfo1.GetParameters().Length..."; true) && + minfo1.GetParameters().Length = 2 && + not minfo2.IsStatic && + minfo2.Name = "InstanceAddWithWitnesses" && + (printfn "checking minfo2.GetParameters().Length = %d..." (minfo2.GetParameters().Length); true) && + minfo2.GetParameters().Length = 3 && + (printfn "checking witnessArgs.Length..."; true) && + witnessArgs.Length = 1 && + (printfn "checking args.Length..."; true) && + args.Length = 2 && + (printfn "witnessArgs..."; true) && + (match witnessArgs with [ Lambda _ ] -> true | _ -> false) && + (printfn "args..."; true) && + (match args with [ _; _ ] -> true | _ -> false) + | CallWithWitnesses(None, minfo1, minfo2, witnessArgs, args) -> + printfn "no object..." + false + | _ -> false) + + test "check CallWithWitnesses all operators)" + (let tests = + [ <@@ sin 1.0 @@>, true + <@@ sin 1.0f @@>, true + <@@ sign 1.0f @@>, true + <@@ sqrt 1.0f @@>, true + <@@ 2.0f ** 2.0f @@>, true + <@@ atan2 3.0 4.0 @@>, true + <@@ 1.0f + 4.0f @@>, true + <@@ 1.0f - 4.0f @@>, true + <@@ 1.0f * 4.0f @@>, true + <@@ 1.0M * 4.0M @@>, true + <@@ 1.0f / 4.0f @@>, true + <@@ 1 % 4 @@>, true + <@@ -(4.0M) @@>, true + + <@@ 1y <<< 3 @@>, true + <@@ 1uy <<< 3 @@>, true + <@@ 1s <<< 3 @@>, true + <@@ 1us <<< 3 @@>, true + <@@ 1 <<< 3 @@>, true + <@@ 1u <<< 3 @@>, true + <@@ 1L <<< 3 @@>, true + <@@ 1UL <<< 3 @@>, true + <@@ LanguagePrimitives.GenericOne <<< 3 @@>, false + <@@ LanguagePrimitives.GenericOne <<< 3 @@>, false + + <@@ 1y >>> 3 @@>, true + <@@ 1uy >>> 3 @@>, true + <@@ 1s >>> 3 @@>, true + <@@ 1us >>> 3 @@>, true + <@@ 1 >>> 3 @@>, true + <@@ 1u >>> 3 @@>, true + <@@ 1L >>> 3 @@>, true + <@@ 1UL >>> 3 @@>, true + <@@ LanguagePrimitives.GenericOne >>> 3 @@>, false + <@@ LanguagePrimitives.GenericOne >>> 3 @@>, false + + <@@ 1y &&& 3y @@>, true + <@@ 1uy &&& 3uy @@>, true + <@@ 1s &&& 3s @@>, true + <@@ 1us &&& 3us @@>, true + <@@ 1 &&& 3 @@>, true + <@@ 1u &&& 3u @@>, true + <@@ 1L &&& 3L @@>, true + <@@ 1UL &&& 3UL @@>, true + <@@ LanguagePrimitives.GenericOne &&& LanguagePrimitives.GenericOne @@>, false + <@@ LanguagePrimitives.GenericOne &&& LanguagePrimitives.GenericOne @@>, false + + <@@ 1y ||| 3y @@>, true + <@@ 1uy ||| 3uy @@>, true + <@@ 1s ||| 3s @@>, true + <@@ 1us ||| 3us @@>, true + <@@ 1 ||| 3 @@>, true + <@@ 1u ||| 3u @@>, true + <@@ 1L ||| 3L @@>, true + <@@ 1UL ||| 3UL @@>, true + <@@ LanguagePrimitives.GenericOne ||| LanguagePrimitives.GenericOne @@>, false + <@@ LanguagePrimitives.GenericOne ||| LanguagePrimitives.GenericOne @@>, false + + <@@ 1y ^^^ 3y @@>, true + <@@ 1uy ^^^ 3uy @@>, true + <@@ 1s ^^^ 3s @@>, true + <@@ 1us ^^^ 3us @@>, true + <@@ 1 ^^^ 3 @@>, true + <@@ 1u ^^^ 3u @@>, true + <@@ 1L ^^^ 3L @@>, true + <@@ 1UL ^^^ 3UL @@>, true + <@@ LanguagePrimitives.GenericOne ^^^ LanguagePrimitives.GenericOne @@>, false + <@@ LanguagePrimitives.GenericOne ^^^ LanguagePrimitives.GenericOne @@>, false + + <@@ ~~~3y @@>, true + <@@ ~~~3uy @@>, true + <@@ ~~~3s @@>, true + <@@ ~~~3us @@>, true + <@@ ~~~3 @@>, true + <@@ ~~~3u @@>, true + <@@ ~~~3L @@>, true + <@@ ~~~3UL @@>, true + <@@ ~~~LanguagePrimitives.GenericOne @@>, false + <@@ ~~~LanguagePrimitives.GenericOne @@>, false + + <@@ byte 3uy @@>, true + <@@ byte 3y @@>, true + <@@ byte 3s @@>, true + <@@ byte 3us @@>, true + <@@ byte 3 @@>, true + <@@ byte 3u @@>, true + <@@ byte 3L @@>, true + <@@ byte 3UL @@>, true + <@@ byte 3.0f @@>, true + <@@ byte 3.0 @@>, true + <@@ byte LanguagePrimitives.GenericOne @@>, false + <@@ byte LanguagePrimitives.GenericOne @@>, false + <@@ byte 3.0M @@>, true + <@@ byte "3" @@>, false + + <@@ sbyte 3uy @@>, true + <@@ sbyte 3y @@>, true + <@@ sbyte 3s @@>, true + <@@ sbyte 3us @@>, true + <@@ sbyte 3 @@>, true + <@@ sbyte 3u @@>, true + <@@ sbyte 3L @@>, true + <@@ sbyte 3UL @@>, true + <@@ sbyte 3.0f @@>, true + <@@ sbyte 3.0 @@>, true + <@@ sbyte LanguagePrimitives.GenericOne @@>, false + <@@ sbyte LanguagePrimitives.GenericOne @@>, false + <@@ sbyte 3.0M @@>, true + <@@ sbyte "3" @@>, false + + <@@ int16 3uy @@>, true + <@@ int16 3y @@>, true + <@@ int16 3s @@>, true + <@@ int16 3us @@>, true + <@@ int16 3 @@>, true + <@@ int16 3u @@>, true + <@@ int16 3L @@>, true + <@@ int16 3UL @@>, true + <@@ int16 3.0f @@>, true + <@@ int16 3.0 @@>, true + <@@ int16 LanguagePrimitives.GenericOne @@>, false + <@@ int16 LanguagePrimitives.GenericOne @@>, false + <@@ int16 3.0M @@>, true + <@@ int16 "3" @@>, false + + <@@ uint16 3uy @@>, true + <@@ uint16 3y @@>, true + <@@ uint16 3s @@>, true + <@@ uint16 3us @@>, true + <@@ uint16 3 @@>, true + <@@ uint16 3u @@>, true + <@@ uint16 3L @@>, true + <@@ uint16 3UL @@>, true + <@@ uint16 3.0f @@>, true + <@@ uint16 3.0 @@>, true + <@@ uint16 LanguagePrimitives.GenericOne @@>, false + <@@ uint16 LanguagePrimitives.GenericOne @@>, false + <@@ uint16 3.0M @@>, true + <@@ uint16 "3" @@>, false + + <@@ int32 3uy @@>, true + <@@ int32 3y @@>, true + <@@ int32 3s @@>, true + <@@ int32 3us @@>, true + <@@ int32 3 @@>, true + <@@ int32 3u @@>, true + <@@ int32 3L @@>, true + <@@ int32 3UL @@>, true + <@@ int32 3.0f @@>, true + <@@ int32 3.0 @@>, true + <@@ int32 LanguagePrimitives.GenericOne @@>, false + <@@ int32 LanguagePrimitives.GenericOne @@>, false + <@@ int32 3.0M @@>, true + <@@ int32 "3" @@>, false + + <@@ uint32 3uy @@>, true + <@@ uint32 3y @@>, true + <@@ uint32 3s @@>, true + <@@ uint32 3us @@>, true + <@@ uint32 3 @@>, true + <@@ uint32 3u @@>, true + <@@ uint32 3L @@>, true + <@@ uint32 3UL @@>, true + <@@ uint32 3.0f @@>, true + <@@ uint32 3.0 @@>, true + <@@ uint32 LanguagePrimitives.GenericOne @@>, false + <@@ uint32 LanguagePrimitives.GenericOne @@>, false + <@@ uint32 3.0M @@>, true + <@@ uint32 "3" @@>, false + + <@@ int64 3uy @@>, true + <@@ int64 3y @@>, true + <@@ int64 3s @@>, true + <@@ int64 3us @@>, true + <@@ int64 3 @@>, true + <@@ int64 3u @@>, true + <@@ int64 3L @@>, true + <@@ int64 3UL @@>, true + <@@ int64 3.0f @@>, true + <@@ int64 3.0 @@>, true + <@@ int64 LanguagePrimitives.GenericOne @@>, false + <@@ int64 LanguagePrimitives.GenericOne @@>, false + <@@ int64 3.0M @@>, true + <@@ int64 "3" @@>, false + + <@@ uint64 3uy @@>, true + <@@ uint64 3y @@>, true + <@@ uint64 3s @@>, true + <@@ uint64 3us @@>, true + <@@ uint64 3 @@>, true + <@@ uint64 3u @@>, true + <@@ uint64 3L @@>, true + <@@ uint64 3UL @@>, true + <@@ uint64 3.0f @@>, true + <@@ uint64 3.0 @@>, true + <@@ uint64 LanguagePrimitives.GenericOne @@>, false + <@@ uint64 LanguagePrimitives.GenericOne @@>, false + <@@ uint64 3.0M @@>, true + <@@ uint64 "3" @@>, false + + <@@ nativeint 3uy @@>, true + <@@ nativeint 3y @@>, true + <@@ nativeint 3s @@>, true + <@@ nativeint 3us @@>, true + <@@ nativeint 3 @@>, true + <@@ nativeint 3u @@>, true + <@@ nativeint 3L @@>, true + <@@ nativeint 3UL @@>, true + <@@ nativeint 3.0f @@>, true + <@@ nativeint 3.0 @@>, true + <@@ nativeint LanguagePrimitives.GenericOne @@>, false + <@@ nativeint LanguagePrimitives.GenericOne @@>, false + //<@@ nativeint 3.0M @@>, false + //<@@ nativeint "3" @@>, false + + <@@ unativeint 3uy @@>, true + <@@ unativeint 3y @@>, true + <@@ unativeint 3s @@>, true + <@@ unativeint 3us @@>, true + <@@ unativeint 3 @@>, true + <@@ unativeint 3u @@>, true + <@@ unativeint 3L @@>, true + <@@ unativeint 3UL @@>, true + <@@ unativeint 3.0f @@>, true + <@@ unativeint 3.0 @@>, true + <@@ unativeint LanguagePrimitives.GenericOne @@>, false + <@@ unativeint LanguagePrimitives.GenericOne @@>, false + //<@@ unativeint 3.0M @@>, true + //<@@ unativeint "3" @@>, true + + <@@ LanguagePrimitives.GenericZero @@>, true + <@@ LanguagePrimitives.GenericZero @@>, true + <@@ LanguagePrimitives.GenericZero @@>, true + <@@ LanguagePrimitives.GenericZero @@>, true + <@@ LanguagePrimitives.GenericZero @@>, true + <@@ LanguagePrimitives.GenericZero @@>, true + <@@ LanguagePrimitives.GenericOne @@>, true + <@@ LanguagePrimitives.GenericOne @@>, true + <@@ LanguagePrimitives.GenericOne @@>, true + <@@ LanguagePrimitives.GenericOne @@>, true + <@@ LanguagePrimitives.GenericOne @@>, true + <@@ LanguagePrimitives.GenericOne @@>, true + <@@ List.sum [ 1; 2 ] @@>, true + <@@ List.sum [ 1.0f; 2.0f ] @@>, true + <@@ List.sum [ 1.0; 2.0 ] @@>, true + <@@ List.sum [ 1.0M; 2.0M ] @@>, true + <@@ List.average [ 1.0; 2.0 ] @@>, true + <@@ List.average [ 1.0f; 2.0f ] @@>, true + <@@ List.average [ 1.0M; 2.0M ] @@>, true + ] + + tests |> List.forall (fun (test, canEval) -> + if canEval then + printfn "--> checking we can evaluate %A" test + FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation test |> ignore + printfn "<-- evaluated!" + else + printfn "skipping evaluation of %A because LinqExpressionConverter can't handle it" test + printfn "checking %A" test + match test with + | CallWithWitnesses(None, minfo1, minfo2, witnessArgs, args) -> + minfo1.IsStatic && + minfo2.IsStatic && + minfo2.Name = minfo1.Name + "WithWitnesses" && + (* + (printfn "checking minfo2.GetParameters().Length = %d..." (minfo2.GetParameters().Length); true) && + minfo2.GetParameters().Length = 3 && + (printfn "checking witnessArgs.Length..."; true) && + witnessArgs.Length = 1 && + (printfn "checking args.Length..."; true) && + args.Length = 2 && + (printfn "witnessArgs..."; true) && + (match witnessArgs with [ Lambda _ ] -> true | _ -> false) && + (printfn "args..."; true) && + (match args with [ _; _ ] -> true | _ -> false) + *) + true + | _ -> false)) + +module MoreWitnessTests = + + open System.Runtime.CompilerServices + open System.IO + + // TODO - ths fails + //[] + module Tests = + let inline f0 (x: 'T) : (unit -> 'T) list = + [] + + let inline f (x: 'T) : (unit -> 'T) list = + [(fun () -> x + x)] + + type C() = + member inline __.F(x: 'T) = x + x + + [] + module M = + + type C with + member inline __.F2(x: 'T) = x + x + static member inline F2Static(x: 'T) = x + x + + [] + type FileExt = + [] + static member CreateDirectory(fileInfo: FileInfo) = + Directory.CreateDirectory fileInfo.Directory.FullName + + [] + static member inline F3(s: string, x: 'T) = + x + x + + [] + static member inline F4(s: string, x1: 'T, x2: 'T) = + x1 + x2 + + + [] + module Usage = + let q0 = <@ f0 3 @> + let q1 = <@ f 3 @> + let q2 = <@ C().F(3) @> + let q3 = <@ C().F2(3) @> + let q4 = <@ C.F2Static(3) @> + let q5 = <@ "".F3(3) @> + let q6 = <@ "".F4(3, 4) @> + + check "wekncjeck1" (q0.ToString()) "Call (None, f0, [Value (3)])" + check "wekncjeck2" (q1.ToString()) "Call (None, f, [Value (3)])" + check "wekncjeck3" (q2.ToString()) "Call (Some (NewObject (C)), F, [Value (3)])" + check "wekncjeck4" (q3.ToString()) "Call (None, C.F2, [NewObject (C), Value (3)])" + check "wekncjeck5" (q4.ToString()) "Call (None, C.F2Static.Static, [Value (3)])" + check "wekncjeck6" (q5.ToString()) "Call (None, F3, [Value (\"\"), Value (3)])" + check "wekncjeck7" (q6.ToString()) "Call (None, F4, [Value (\"\"), Value (3), Value (4)])" + + check "ewlknweknl1" (FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation q0) (box ([] : (unit -> int) list)) + check "ewlknweknl2" (match FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation q1 with :? ((unit -> int) list) as x -> x.[0] ()) 6 + check "ewlknweknl3" (match FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation q2 with :? int as x -> x) 6 + check "ewlknweknl4" (match FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation q3 with :? int as x -> x) 6 + check "ewlknweknl5" (match FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation q4 with :? int as x -> x) 6 + check "ewlknweknl6" (match FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation q5 with :? int as x -> x) 6 + check "ewlknweknl7" (match FSharp.Linq.RuntimeHelpers.LeafExpressionConverter.EvaluateQuotation q6 with :? int as x -> x) 7 #if !FX_RESHAPED_REFLECTION module TestAssemblyAttributes = @@ -3192,8 +3662,8 @@ let aa = stdout.WriteLine "Test Passed" System.IO.File.WriteAllText("test.ok","ok") exit 0 - | _ -> - stdout.WriteLine "Test Failed" + | errs -> + printfn "Test Failed, errors = %A" errs exit 1 #endif diff --git a/tests/fsharp/single-test.fs b/tests/fsharp/single-test.fs index f593a721232..780fa1c3956 100644 --- a/tests/fsharp/single-test.fs +++ b/tests/fsharp/single-test.fs @@ -249,29 +249,28 @@ let singleTestBuildAndRunCore cfg copyFiles p = try File.Delete(Path.Combine(directory, "FSharp.Core.dll")) with _ -> () emitFile targetsFileName targetsBody emitFile overridesFileName overridesBody + let propsBody = generateProps compilerType cfg.BUILD_CONFIG + emitFile propsFileName propsBody + let projectBody = generateProjectArtifacts pc outputType targetFramework cfg.BUILD_CONFIG + emitFile projectFileName projectBody + printfn "------ Overrides file: %s" overridesFileName + printfn "%s" overridesBody + printfn "------ Targets file: %s" targetsFileName + printfn "%s" targetsBody + printfn "------ Props file: %s" propsFileName + printfn "%s" propsBody + printfn "------ Project file: %s" projectFileName + printfn "%s" projectBody + printfn "------ Execute:" + use testOkFile = new FileGuard(Path.Combine(directory, "test.ok")) if outputType = OutputType.Exe then - let executeFsc testCompilerVersion targetFramework = - let propsBody = generateProps testCompilerVersion cfg.BUILD_CONFIG - emitFile propsFileName propsBody - let projectBody = generateProjectArtifacts pc outputType targetFramework cfg.BUILD_CONFIG - emitFile projectFileName projectBody - use testOkFile = new FileGuard(Path.Combine(directory, "test.ok")) - exec { cfg with Directory = directory } cfg.DotNetExe (sprintf "run -f %s" targetFramework) - testOkFile.CheckExists() - executeFsc compilerType targetFramework + exec { cfg with Directory = directory } cfg.DotNetExe (sprintf "run -f %s -v:n" targetFramework) else - let executeFsi testCompilerVersion targetFramework = - let propsBody = generateProps testCompilerVersion cfg.BUILD_CONFIG - emitFile propsFileName propsBody - let projectBody = generateProjectArtifacts pc outputType targetFramework cfg.BUILD_CONFIG - emitFile projectFileName projectBody - use testOkFile = new FileGuard(Path.Combine(directory, "test.ok")) - exec { cfg with Directory = directory } cfg.DotNetExe "build /t:RunFSharpScript" - testOkFile.CheckExists() - executeFsi compilerType targetFramework - result <- true + exec { cfg with Directory = directory } cfg.DotNetExe "build /t:RunFSharpScript -v:n" + testOkFile.CheckExists() + result <- true finally - if result <> false then + if result then Directory.Delete(directory, true) else printfn "Configuration: %s" cfg.Directory diff --git a/tests/fsharpqa/Source/Printing/Quotation01.fs b/tests/fsharpqa/Source/Printing/Quotation01.fs index bf6ce9e2479..48aab89514f 100644 --- a/tests/fsharpqa/Source/Printing/Quotation01.fs +++ b/tests/fsharpqa/Source/Printing/Quotation01.fs @@ -1,7 +1,5 @@ // #NoMT #Printing // Regression test for FSHARP1.0:524 -//val it : Quotations.Expr = Value \(1\) {CustomAttributes = \[||\]; -// Raw = \.\.\.; -// Type = System\.Int32;} +//val it : Quotations.Expr = Value \(1\) <@ 1 @>;; exit 0;;