Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion eng/Build.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -497,7 +497,7 @@ try {
Create-Directory $resultsRoot
UpdatePath
$env:HOSTED_COMPILER = 1
$env:CSC_PIPE = "$nugetPackages\Microsoft.Net.Compilers\2.7.0\tools\csc.exe"
$env:CSC_PIPE = "$nugetPackages\Microsoft.Net.Compilers\3.9.0\tools\csc.exe"
$env:FSCOREDLLPATH = "$ArtifactsDir\bin\fsc\$configuration\net472\FSharp.Core.dll"
$env:LINK_EXE = "$RepoRoot\tests\fsharpqa\testenv\bin\link\link.exe"
$env:OSARCH = $env:PROCESSOR_ARCHITECTURE
Expand Down
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@
<FSharpDataTypeProvidersVersion>4.3.0.0</FSharpDataTypeProvidersVersion>
<MicrosoftCompositionVersion>1.0.30</MicrosoftCompositionVersion>
<MicrosoftMSXMLVersion>8.0.0</MicrosoftMSXMLVersion>
<MicrosoftNetCompilersVersion>2.7.0</MicrosoftNetCompilersVersion>
<MicrosoftNetCompilersVersion>3.9.0</MicrosoftNetCompilersVersion>
<MicrosoftNETCoreAppRefVersion>3.1.0</MicrosoftNETCoreAppRefVersion>
<MicrosoftNETCoreILDAsmVersion>5.0.0-preview.7.20364.11</MicrosoftNETCoreILDAsmVersion>
<MicrosoftNETCoreILAsmVersion>5.0.0-preview.7.20364.11</MicrosoftNETCoreILAsmVersion>
Expand Down
2 changes: 2 additions & 0 deletions src/fsharp/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -8243,6 +8243,8 @@ and TcLookupThen cenv overallTy env tpenv mObjExpr objExpr objExprTy longId dela
if isNil meths then error (Error (FSComp.SR.tcPropertyIsNotReadable nm, mItem))
TcMethodApplicationThen cenv env overallTy None tpenv tyargsOpt objArgs mExprAndItem mItem nm ad PossiblyMutates true meths afterResolution NormalValUse args atomicFlag delayed
else
if pinfo.SetterIsInitOnly then
errorR (Error (FSComp.SR.tcPropertyCannotBeSet1 nm, mItem))
let args = if pinfo.IsIndexer then args else []
let mut = (if isStructTy cenv.g (tyOfExpr cenv.g objExpr) then DefinitelyMutates else PossiblyMutates)
TcMethodApplicationThen cenv env overallTy None tpenv tyargsOpt objArgs mStmt mItem nm ad mut true meths afterResolution NormalValUse (args @ [e2]) atomicFlag []
Expand Down
4 changes: 2 additions & 2 deletions src/fsharp/MethodCalls.fs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ type AssignedItemSetterTarget =
| AssignedRecdFieldSetter of RecdFieldInfo

/// Represents the resolution of a caller argument as a named-setter argument
type AssignedItemSetter<'T> = AssignedItemSetter of Ident * AssignedItemSetterTarget * CallerArg<'T>
type AssignedItemSetter<'T> = AssignedItemSetter of name: Ident * setterTarget: AssignedItemSetterTarget * callerArg: CallerArg<'T>

type CallerNamedArg<'T> =
| CallerNamedArg of Ident * CallerArg<'T>
Expand Down Expand Up @@ -435,7 +435,7 @@ type CalledMeth<'T>
let pinfos = GetIntrinsicPropInfoSetsOfType infoReader (Some nm) ad AllowMultiIntfInstantiations.Yes IgnoreOverrides id.idRange returnedObjTy
let pinfos = pinfos |> ExcludeHiddenOfPropInfos g infoReader.amap m
match pinfos with
| [pinfo] when pinfo.HasSetter && not pinfo.IsIndexer ->
| [pinfo] when pinfo.HasSetter && not pinfo.IsIndexer && not pinfo.SetterIsInitOnly ->
let pminfo = pinfo.SetterMethod
let pminst = freshenMethInfo m pminfo
Choice1Of2(AssignedItemSetter(id, AssignedPropSetter(pinfo, pminfo, pminst), e))
Expand Down
7 changes: 6 additions & 1 deletion src/fsharp/MethodCalls.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,12 @@ type AssignedItemSetterTarget =
/// Represents the resolution of a caller argument as a named-setter argument
type AssignedItemSetter<'T> =
| AssignedItemSetter of
Ident * AssignedItemSetterTarget * CallerArg<'T>
/// named-setter identifier
name: Ident *
/// named-setter target
setterTarget: AssignedItemSetterTarget *
/// caller argument that resolved into AssignedItemSetter
callerArg: CallerArg<'T>

type CallerNamedArg<'T> =
| CallerNamedArg of Ident * CallerArg<'T>
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/NameResolution.fs
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ type Item =
| Event of EventInfo

/// Represents the resolution of a name to a property
| Property of string * PropInfo list
| Property of propertyName: string * propertyInfos: PropInfo list

/// Represents the resolution of a name to a group of methods.
| MethodGroup of displayName: string * methods: MethInfo list * uninstantiatedMethodOpt: MethInfo option
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/NameResolution.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type Item =
| Event of EventInfo

/// Represents the resolution of a name to a property
| Property of string * PropInfo list
| Property of propertyName: string * propertyInfos: PropInfo list

/// Represents the resolution of a name to a group of methods.
| MethodGroup of displayName: string * methods: MethInfo list * uninstantiatedMethodOpt: MethInfo option
Expand Down
2 changes: 1 addition & 1 deletion src/fsharp/absil/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -719,7 +719,7 @@ and [<RequireQualifiedAccess; StructuralEquality; StructuralComparison; Structur
| Byref of ILType
| FunctionPointer of ILCallingSignature
| TypeVar of uint16
| Modified of bool * ILTypeRef * ILType
| Modified of isRequired: bool * modifierClass: ILTypeRef * modifiedType: ILType

member x.BasicQualifiedName =
match x with
Expand Down
6 changes: 3 additions & 3 deletions src/fsharp/absil/il.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -276,11 +276,11 @@ type ILType =
/// Custom modifiers.
| Modified of
/// True if modifier is "required".
bool *
isRequired: bool *
/// The class of the custom modifier.
ILTypeRef *
modifierClass: ILTypeRef *
/// The type being modified.
ILType
modifiedType: ILType

member TypeSpec: ILTypeSpec

Expand Down
14 changes: 14 additions & 0 deletions src/fsharp/infos.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1890,6 +1890,12 @@ type ILPropInfo =
/// Indicates if the IL property has a 'set' method
member x.HasSetter = Option.isSome x.RawMetadata.SetMethod

member x.SetterIsInitOnly =
match x.SetterMethod.ILMethodRef.ReturnType with
| ILType.Modified(modifierClass=modifierClass) ->
modifierClass.BasicQualifiedName = "System.Runtime.CompilerServices.IsExternalInit"
| _ -> false

/// Indicates if the IL property is static
member x.IsStatic = (x.RawMetadata.CallingConv = ILThisConvention.Static)

Expand Down Expand Up @@ -2016,6 +2022,14 @@ type PropInfo =
| ProvidedProp(_, pi, m) -> pi.PUntaint((fun pi -> pi.CanWrite), m)
#endif

member x.SetterIsInitOnly =
match x with
| ILProp ilpinfo -> ilpinfo.SetterIsInitOnly
| FSProp _ -> false // F# doesn't support this
#if !NO_EXTENSIONTYPING
| ProvidedProp _ -> false
#endif

/// Indicates if this is an extension member
member x.IsExtensionMember =
match x.ArbitraryValRef with
Expand Down
6 changes: 6 additions & 0 deletions src/fsharp/infos.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,9 @@ type ILPropInfo =
/// Indicates if the IL property has a 'set' method
member HasSetter: bool

/// Indicates if the IL property setter is marked as 'init'
member SetterIsInitOnly: bool

/// Get the declaring IL type of the IL property, including any generic instantiation
member ILTypeInfo: ILTypeInfo

Expand Down Expand Up @@ -818,6 +821,9 @@ type PropInfo =
/// Indicates if this property has an associated setter method.
member HasSetter: bool

/// Indicates ...
member SetterIsInitOnly: bool

member ImplementedSlotSignatures: SlotSig list

/// Indicates if this property is marked 'override' and thus definitely overrides another property.
Expand Down
4 changes: 2 additions & 2 deletions tests/FSharp.Test.Utilities/TestFramework.fs
Original file line number Diff line number Diff line change
Expand Up @@ -285,8 +285,8 @@ let config configurationName envVars =
let packagesDir = getPackagesDir ()
let requirePackage = requireFile packagesDir
let requireArtifact = requireFile artifactsBinPath
let CSC = requirePackage ("Microsoft.Net.Compilers" ++ "2.7.0" ++ "tools" ++ "csc.exe")
let VBC = requirePackage ("Microsoft.Net.Compilers" ++ "2.7.0" ++ "tools" ++ "vbc.exe")
let CSC = requirePackage ("Microsoft.Net.Compilers" ++ "3.9.0" ++ "tools" ++ "csc.exe")
let VBC = requirePackage ("Microsoft.Net.Compilers" ++ "3.9.0" ++ "tools" ++ "vbc.exe")
let ILDASM_EXE = if operatingSystem = "win" then "ildasm.exe" else "ildasm"
let ILDASM = requirePackage (("runtime." + operatingSystem + "-" + architectureMoniker + ".Microsoft.NETCore.ILDAsm") ++ coreClrRuntimePackageVersion ++ "runtimes" ++ (operatingSystem + "-" + architectureMoniker) ++ "native" ++ ILDASM_EXE)
let ILASM_EXE = if operatingSystem = "win" then "ilasm.exe" else "ilasm"
Expand Down
6 changes: 6 additions & 0 deletions tests/fsharp/tests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1851,6 +1851,12 @@ module CoreTests =
fsc cfg @"%s /target:library /out:fs.dll" cfg.fsc_flags ["fs.fs"]
singleNegTest cfg "calls"

[<Test>]
let ``play nice with init properties and assignment syntax``() =
let cfg = testConfig "typecheck/init-property"
csc cfg "%s /target:library /out:niceinit.dll" cfg.csc_flags ["niceinit.cs"]
singleNegTest cfg "niceinit"

#endif

module VersionTests =
Expand Down
12 changes: 12 additions & 0 deletions tests/fsharp/typecheck/init-property/niceinit.bsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

niceinit.fsx(3,25,3,28): typecheck error FS0495: The object constructor 'NiceInit' has no argument or settable return property 'Val'. The required signature is NiceInit() : NiceInit.

niceinit.fsx(6,1,6,14): typecheck error FS0810: Property 'Val' cannot be set

niceinit.fsx(13,47,13,50): typecheck error FS0495: The member or object constructor 'mkInlineNiceInit' has no argument or settable return property 'Val'. The required signature is static member StraightNewFactory.mkInlineNiceInit : unit -> NiceInit.

niceinit.fsx(14,41,14,44): typecheck error FS0495: The member or object constructor 'mkNiceInit' has no argument or settable return property 'Val'. The required signature is static member StraightNewFactory.mkNiceInit : unit -> NiceInit.

niceinit.fsx(26,73,26,76): typecheck error FS0495: The member or object constructor 'mkInlineNiceInit' has no argument or settable return property 'Val'. The required signature is static member IntermediateVariableWithInterleavedOpFactory.mkInlineNiceInit : unit -> NiceInit.

niceinit.fsx(27,67,27,70): typecheck error FS0495: The member or object constructor 'mkNiceInit' has no argument or settable return property 'Val'. The required signature is static member IntermediateVariableWithInterleavedOpFactory.mkNiceInit : unit -> NiceInit.
10 changes: 10 additions & 0 deletions tests/fsharp/typecheck/init-property/niceinit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace System.Runtime.CompilerServices{

internal class IsExternalInit {}
}

public class NiceInit {
public NiceInit() {}
public int Val {get; init;}
public int OkVal {get; set;}
}
27 changes: 27 additions & 0 deletions tests/fsharp/typecheck/init-property/niceinit.fsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#r @"niceinit.dll"

let niceinit = NiceInit(Val = 1);;

let niceinit2 = NiceInit();;
niceinit2.Val <- 5;;
niceinit2.set_Val 5;;

type StraightNewFactory =
static member inline mkInlineNiceInit () = NiceInit()
static member mkNiceInit () = NiceInit()
;;
let ni1 = StraightNewFactory.mkInlineNiceInit(Val=1);;
let ni2 = StraightNewFactory.mkNiceInit(Val=1);;

type IntermediateVariableWithInterleavedOpFactory =
static member inline mkInlineNiceInit () =
let n = NiceInit()
printfn "inline nice init"
n
static member mkNiceInit () =
let n = NiceInit()
printfn "nice init"
n
;;
let ni3 = IntermediateVariableWithInterleavedOpFactory.mkInlineNiceInit(Val=1);;
let ni4 = IntermediateVariableWithInterleavedOpFactory.mkNiceInit(Val=1);;