未验证 提交 ff078e94 编写于 作者: D Don Syme 提交者: GitHub

Add entity.DeclaringEntity to F# Compiler Service (#4633)

* Add DeclaringEntity

* extend tests to cover namespaces

* extend tests to cover namespaces

* build on Mono 5.10

* bump FCS version

* various comments and debugging improvements

* code review
上级 8388cf53
......@@ -60,9 +60,9 @@ which does things like:
You can push the packages if you have permissions, either automatically using ``build Release`` or manually
set APIKEY=...
..\fsharp\.nuget\nuget.exe push %HOMEDRIVE%%HOMEPATH%\Downloads\FSharp.Compiler.Service.22.0.2.nupkg %APIKEY% -Source https://nuget.org
..\fsharp\.nuget\nuget.exe push %HOMEDRIVE%%HOMEPATH%\Downloads\FSharp.Compiler.Service.MSBuild.v12.22.0.2.nupkg %APIKEY% -Source https://nuget.org
..\fsharp\.nuget\nuget.exe push %HOMEDRIVE%%HOMEPATH%\Downloads\FSharp.Compiler.Service.ProjectCracker.22.0.2.nupkg %APIKEY% -Source https://nuget.org
..\fsharp\.nuget\nuget.exe push %HOMEDRIVE%%HOMEPATH%\Downloads\FSharp.Compiler.Service.22.0.3.nupkg %APIKEY% -Source https://nuget.org
..\fsharp\.nuget\nuget.exe push %HOMEDRIVE%%HOMEPATH%\Downloads\FSharp.Compiler.Service.MSBuild.v12.22.0.3.nupkg %APIKEY% -Source https://nuget.org
..\fsharp\.nuget\nuget.exe push %HOMEDRIVE%%HOMEPATH%\Downloads\FSharp.Compiler.Service.ProjectCracker.22.0.3.nupkg %APIKEY% -Source https://nuget.org
### Use of Paket and FAKE
......
#### 22.0.3
* [Add entity.DeclaringEntity](https://github.com/Microsoft/visualfsharp/pull/4633), [FCS feature request](https://github.com/fsharp/FSharp.Compiler.Service/issues/830)
#### 22.0.2
* Use correct version number in DLLs (needed until https://github.com/Microsoft/visualfsharp/issues/3113 is fixed)
......
......@@ -3,7 +3,7 @@
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<VersionPrefix>22.0.2</VersionPrefix>
<VersionPrefix>22.0.3</VersionPrefix>
<OtherFlags>--version:$(VersionPrefix)</OtherFlags>
<!-- FSharp.Compiler.Tools is currently only used to get a working FSI.EXE to execute some scripts during the build -->
<!-- The LKG FSI.EXE requires MSBuild 15 to be installed, which is painful -->
......
......@@ -408,8 +408,6 @@ type ILAssemblyRef(data) =
ILAssemblyRef.Create(aname.Name,None,publicKey,retargetable,version,locale)
member aref.QualifiedName =
let b = new System.Text.StringBuilder(100)
let add (s:string) = (b.Append(s) |> ignore)
......@@ -478,13 +476,6 @@ type ILScopeRef =
member x.AssemblyRef = match x with ILScopeRef.Assembly x -> x | _ -> failwith "not an assembly reference"
member scoref.QualifiedName =
match scoref with
| ILScopeRef.Local -> ""
| ILScopeRef.Module mref -> "module "^mref.Name
| ILScopeRef.Assembly aref when aref.Name = "mscorlib" -> ""
| ILScopeRef.Assembly aref -> aref.QualifiedName
member scoref.QualifiedNameWithNoShortPrimaryAssembly =
match scoref with
| ILScopeRef.Local -> ""
| ILScopeRef.Module mref -> "module "+mref.Name
......@@ -602,18 +593,12 @@ type ILTypeRef =
member tref.BasicQualifiedName =
(String.concat "+" (tref.Enclosing @ [ tref.Name ] )).Replace(",", @"\,")
member tref.AddQualifiedNameExtensionWithNoShortPrimaryAssembly(basic) =
let sco = tref.Scope.QualifiedNameWithNoShortPrimaryAssembly
if sco = "" then basic else String.concat ", " [basic;sco]
member tref.QualifiedNameWithNoShortPrimaryAssembly =
tref.AddQualifiedNameExtensionWithNoShortPrimaryAssembly(tref.BasicQualifiedName)
member tref.QualifiedName =
let basic = tref.BasicQualifiedName
member tref.AddQualifiedNameExtension(basic) =
let sco = tref.Scope.QualifiedName
if sco = "" then basic else String.concat ", " [basic;sco]
member tref.QualifiedName =
tref.AddQualifiedNameExtension(tref.BasicQualifiedName)
override x.ToString() = x.FullName
......@@ -624,22 +609,30 @@ and
{ tspecTypeRef: ILTypeRef;
/// The type instantiation if the type is generic.
tspecInst: ILGenericArgs }
member x.TypeRef=x.tspecTypeRef
member x.Scope=x.TypeRef.Scope
member x.Enclosing=x.TypeRef.Enclosing
member x.Name=x.TypeRef.Name
member x.GenericArgs=x.tspecInst
static member Create(tref,inst) = { tspecTypeRef =tref; tspecInst=inst }
override x.ToString() = x.TypeRef.ToString() + if isNil x.GenericArgs then "" else "<...>"
member x.BasicQualifiedName =
let tc = x.TypeRef.BasicQualifiedName
if isNil x.GenericArgs then
tc
else
tc + "[" + String.concat "," (x.GenericArgs |> List.map (fun arg -> "[" + arg.QualifiedNameWithNoShortPrimaryAssembly + "]")) + "]"
tc + "[" + String.concat "," (x.GenericArgs |> List.map (fun arg -> "[" + arg.QualifiedName + "]")) + "]"
member x.AddQualifiedNameExtensionWithNoShortPrimaryAssembly(basic) =
x.TypeRef.AddQualifiedNameExtensionWithNoShortPrimaryAssembly(basic)
member x.AddQualifiedNameExtension(basic) =
x.TypeRef.AddQualifiedNameExtension(basic)
member x.FullName=x.TypeRef.FullName
......@@ -666,19 +659,19 @@ and [<RequireQualifiedAccess; StructuralEquality; StructuralComparison>]
| ILType.Byref _ty -> failwith "unexpected byref type"
| ILType.FunctionPointer _mref -> failwith "unexpected function pointer type"
member x.AddQualifiedNameExtensionWithNoShortPrimaryAssembly(basic) =
member x.AddQualifiedNameExtension(basic) =
match x with
| ILType.TypeVar _n -> basic
| ILType.Modified(_,_ty1,ty2) -> ty2.AddQualifiedNameExtensionWithNoShortPrimaryAssembly(basic)
| ILType.Array (ILArrayShape(_s),ty) -> ty.AddQualifiedNameExtensionWithNoShortPrimaryAssembly(basic)
| ILType.Value tr | ILType.Boxed tr -> tr.AddQualifiedNameExtensionWithNoShortPrimaryAssembly(basic)
| ILType.Modified(_,_ty1,ty2) -> ty2.AddQualifiedNameExtension(basic)
| ILType.Array (ILArrayShape(_s),ty) -> ty.AddQualifiedNameExtension(basic)
| ILType.Value tr | ILType.Boxed tr -> tr.AddQualifiedNameExtension(basic)
| ILType.Void -> failwith "void"
| ILType.Ptr _ty -> failwith "unexpected pointer type"
| ILType.Byref _ty -> failwith "unexpected byref type"
| ILType.FunctionPointer _mref -> failwith "unexpected function pointer type"
member x.QualifiedNameWithNoShortPrimaryAssembly =
x.AddQualifiedNameExtensionWithNoShortPrimaryAssembly(x.BasicQualifiedName)
member x.QualifiedName =
x.AddQualifiedNameExtension(x.BasicQualifiedName)
member x.TypeSpec =
match x with
......@@ -3301,7 +3294,7 @@ let rec encodeCustomAttrElemType x =
| ILType.Boxed tspec when tspec.Name = tname_String -> [| et_STRING |]
| ILType.Boxed tspec when tspec.Name = tname_Object -> [| 0x51uy |]
| ILType.Boxed tspec when tspec.Name = tname_Type -> [| 0x50uy |]
| ILType.Value tspec -> Array.append [| 0x55uy |] (encodeCustomAttrString tspec.TypeRef.QualifiedNameWithNoShortPrimaryAssembly)
| ILType.Value tspec -> Array.append [| 0x55uy |] (encodeCustomAttrString tspec.TypeRef.QualifiedName)
| ILType.Array (shape, elemType) when shape = ILArrayShape.SingleDimensional ->
Array.append [| et_SZARRAY |] (encodeCustomAttrElemType elemType)
| _ -> failwith "encodeCustomAttrElemType: unrecognized custom element type"
......@@ -3372,8 +3365,8 @@ let rec encodeCustomAttrPrimValue ilg c =
| ILAttribElem.UInt64 x -> u64AsBytes x
| ILAttribElem.Single x -> ieee32AsBytes x
| ILAttribElem.Double x -> ieee64AsBytes x
| ILAttribElem.Type (Some ty) -> encodeCustomAttrString ty.QualifiedNameWithNoShortPrimaryAssembly
| ILAttribElem.TypeRef (Some tref) -> encodeCustomAttrString tref.QualifiedNameWithNoShortPrimaryAssembly
| ILAttribElem.Type (Some ty) -> encodeCustomAttrString ty.QualifiedName
| ILAttribElem.TypeRef (Some tref) -> encodeCustomAttrString tref.QualifiedName
| ILAttribElem.Array (_,elems) ->
[| yield! i32AsBytes elems.Length; for elem in elems do yield! encodeCustomAttrPrimValue ilg elem |]
......@@ -3427,7 +3420,7 @@ let mkPermissionSet (ilg: ILGlobals) (action,attributes: list<(ILTypeRef * (stri
[| yield (byte '.');
yield! z_unsigned_int attributes.Length;
for (tref:ILTypeRef,props) in attributes do
yield! encodeCustomAttrString tref.QualifiedNameWithNoShortPrimaryAssembly
yield! encodeCustomAttrString tref.QualifiedName
let bytes =
[| yield! z_unsigned_int props.Length;
for (nm,typ,value) in props do
......
......@@ -184,15 +184,12 @@ type ILTypeRef =
member QualifiedName: string
#if !NO_EXTENSIONTYPING
member QualifiedNameWithNoShortPrimaryAssembly: string
#endif
interface System.IComparable
/// Type specs and types.
[<Sealed>]
type ILTypeSpec =
/// Create an ILTypeSpec.
static member Create: typeRef:ILTypeRef * instantiation:ILGenericArgs -> ILTypeSpec
/// Which type is being referred to?
......@@ -200,10 +197,19 @@ type ILTypeSpec =
/// The type instantiation if the type is generic, otherwise empty
member GenericArgs: ILGenericArgs
/// Where is the type, i.e. is it in this module, in another module in this assembly or in another assembly?
member Scope: ILScopeRef
/// The list of enclosing type names for a nested type. If non-nil then the first of these also contains the namespace.
member Enclosing: string list
/// The name of the type. This also contains the namespace if Enclosing is empty.
member Name: string
/// The name of the type in the assembly using the '.' notation for nested types.
member FullName: string
interface System.IComparable
and
......@@ -244,13 +250,20 @@ and
ILType
member TypeSpec: ILTypeSpec
member Boxity: ILBoxity
member TypeRef: ILTypeRef
member IsNominal: bool
member GenericArgs: ILGenericArgs
member IsTyvar: bool
member BasicQualifiedName: string
member QualifiedNameWithNoShortPrimaryAssembly: string
member QualifiedName: string
and [<StructuralEquality; StructuralComparison>]
ILCallingSignature =
......@@ -271,13 +284,21 @@ type ILMethodRef =
static member Create: enclosingTypeRef: ILTypeRef * callingConv: ILCallingConv * name: string * genericArity: int * argTypes: ILTypes * returnType: ILType -> ILMethodRef
member DeclaringTypeRef: ILTypeRef
member CallingConv: ILCallingConv
member Name: string
member GenericArity: int
member ArgCount: int
member ArgTypes: ILTypes
member ReturnType: ILType
member CallingSignature: ILCallingSignature
interface System.IComparable
/// Formal identities of fields.
......@@ -295,13 +316,21 @@ type ILMethodSpec =
static member Create: ILType * ILMethodRef * ILGenericArgs -> ILMethodSpec
member MethodRef: ILMethodRef
member DeclaringType: ILType
member GenericArgs: ILGenericArgs
member CallingConv: ILCallingConv
member GenericArity: int
member Name: string
member FormalArgTypes: ILTypes
member FormalReturnType: ILType
interface System.IComparable
/// Field specs. The data given for a ldfld, stfld etc. instruction.
......@@ -311,8 +340,11 @@ type ILFieldSpec =
DeclaringType: ILType }
member DeclaringTypeRef: ILTypeRef
member Name: string
member FormalType: ILType
member ActualType: ILType
/// ILCode labels. In structured code each code label refers to a basic block somewhere in the code of the method.
......
......@@ -5326,7 +5326,6 @@ let CheckSimulateException(tcConfig:TcConfig) =
type RootSigs = Zmap<QualifiedNameOfFile, ModuleOrNamespaceType>
type RootImpls = Zset<QualifiedNameOfFile >
type TypecheckerSigsAndImpls = RootSigsAndImpls of RootSigs * RootImpls * ModuleOrNamespaceType * ModuleOrNamespaceType
let qnameOrder = Order.orderBy (fun (q:QualifiedNameOfFile) -> q.Text)
......@@ -5337,17 +5336,25 @@ type TcState =
tcsTcSigEnv: TcEnv
tcsTcImplEnv: TcEnv
tcsCreatesGeneratedProvidedTypes: bool
/// The accumulated results of type checking for this assembly
tcsRootSigsAndImpls : TypecheckerSigsAndImpls }
tcsRootSigs: RootSigs
tcsRootImpls: RootImpls
tcsCcuSig: ModuleOrNamespaceType }
member x.NiceNameGenerator = x.tcsNiceNameGen
member x.TcEnvFromSignatures = x.tcsTcSigEnv
member x.TcEnvFromImpls = x.tcsTcImplEnv
member x.Ccu = x.tcsCcu
member x.CreatesGeneratedProvidedTypes = x.tcsCreatesGeneratedProvidedTypes
member x.PartialAssemblySignature =
let (RootSigsAndImpls(_rootSigs, _rootImpls, _allSigModulTyp, allImplementedSigModulTyp)) = x.tcsRootSigsAndImpls
allImplementedSigModulTyp
// Assem(a.fsi + b.fsi + c.fsi) (after checking implementation file )
member x.CcuType = x.tcsCcuType
// a.fsi + b.fsi + c.fsi (after checking implementation file for c.fs)
member x.CcuSig = x.tcsCcuSig
member x.NextStateAfterIncrementalFragment(tcEnvAtEndOfLastInput) =
{ x with tcsTcSigEnv = tcEnvAtEndOfLastInput
......@@ -5385,133 +5392,127 @@ let GetInitialTcState(m, ccuName, tcConfig:TcConfig, tcGlobals, tcImports:TcImpo
if tcConfig.compilingFslib then
tcGlobals.fslibCcu.Fixup(ccu)
let rootSigs = Zmap.empty qnameOrder
let rootImpls = Zset.empty qnameOrder
let allSigModulTyp = NewEmptyModuleOrNamespaceType Namespace
let allImplementedSigModulTyp = NewEmptyModuleOrNamespaceType Namespace
{ tcsCcu= ccu
tcsCcuType=ccuType
tcsNiceNameGen=niceNameGen
tcsTcSigEnv=tcEnv0
tcsTcImplEnv=tcEnv0
tcsCreatesGeneratedProvidedTypes=false
tcsRootSigsAndImpls = RootSigsAndImpls (rootSigs, rootImpls, allSigModulTyp, allImplementedSigModulTyp) }
tcsRootSigs = Zmap.empty qnameOrder
tcsRootImpls = Zset.empty qnameOrder
tcsCcuSig = NewEmptyModuleOrNamespaceType Namespace }
/// Typecheck a single file (or interactive entry into F# Interactive)
let TypeCheckOneInputEventually
(checkForErrors, tcConfig:TcConfig, tcImports:TcImports,
tcGlobals, prefixPathOpt, tcSink, tcState: TcState, inp: ParsedInput) =
eventually {
try
let! ctok = Eventually.token
RequireCompilationThread ctok // Everything here requires the compilation thread since it works on the TAST
CheckSimulateException(tcConfig)
let (RootSigsAndImpls(rootSigs, rootImpls, allSigModulTyp, allImplementedSigModulTyp)) = tcState.tcsRootSigsAndImpls
let m = inp.Range
let amap = tcImports.GetImportMap()
let! (topAttrs, implFiles, tcEnvAtEnd, tcSigEnv, tcImplEnv, topSigsAndImpls, ccuType, createsGeneratedProvidedTypes) =
eventually {
match inp with
| ParsedInput.SigFile (ParsedSigFileInput(_, qualNameOfFile, _, _, _) as file) ->
// Check if we've seen this top module signature before.
if Zmap.mem qualNameOfFile rootSigs then
errorR(Error(FSComp.SR.buildSignatureAlreadySpecified(qualNameOfFile.Text), m.StartRange))
let TypeCheckOneInputEventually (checkForErrors, tcConfig:TcConfig, tcImports:TcImports, tcGlobals, prefixPathOpt, tcSink, tcState: TcState, inp: ParsedInput) =
// Check if the implementation came first in compilation order
if Zset.contains qualNameOfFile rootImpls then
errorR(Error(FSComp.SR.buildImplementationAlreadyGivenDetail(qualNameOfFile.Text), m))
eventually {
try
let! ctok = Eventually.token
RequireCompilationThread ctok // Everything here requires the compilation thread since it works on the TAST
// Typecheck the signature file
let! (tcEnv, sigFileType, createsGeneratedProvidedTypes) =
TypeCheckOneSigFile (tcGlobals, tcState.tcsNiceNameGen, amap, tcState.tcsCcu, checkForErrors, tcConfig.conditionalCompilationDefines, tcSink) tcState.tcsTcSigEnv file
CheckSimulateException(tcConfig)
let rootSigs = Zmap.add qualNameOfFile sigFileType rootSigs
let m = inp.Range
let amap = tcImports.GetImportMap()
match inp with
| ParsedInput.SigFile (ParsedSigFileInput(_, qualNameOfFile, _, _, _) as file) ->
// Check if we've seen this top module signature before.
if Zmap.mem qualNameOfFile tcState.tcsRootSigs then
errorR(Error(FSComp.SR.buildSignatureAlreadySpecified(qualNameOfFile.Text), m.StartRange))
// Open the prefixPath for fsi.exe
let tcEnv =
match prefixPathOpt with
| None -> tcEnv
| Some prefixPath ->
let m = qualNameOfFile.Range
TcOpenDecl tcSink tcGlobals amap m m tcEnv prefixPath
// Check if the implementation came first in compilation order
if Zset.contains qualNameOfFile tcState.tcsRootImpls then
errorR(Error(FSComp.SR.buildImplementationAlreadyGivenDetail(qualNameOfFile.Text), m))
let res = (EmptyTopAttrs, None, tcEnv, tcEnv, tcState.tcsTcImplEnv, RootSigsAndImpls(rootSigs, rootImpls, allSigModulTyp, allImplementedSigModulTyp), tcState.tcsCcuType, createsGeneratedProvidedTypes)
return res
// Typecheck the signature file
let! (tcEnv, sigFileType, createsGeneratedProvidedTypes) =
TypeCheckOneSigFile (tcGlobals, tcState.tcsNiceNameGen, amap, tcState.tcsCcu, checkForErrors, tcConfig.conditionalCompilationDefines, tcSink) tcState.tcsTcSigEnv file
| ParsedInput.ImplFile (ParsedImplFileInput(filename, _, qualNameOfFile, _, _, _, _) as file) ->
// Check if we've got an interface for this fragment
let rootSigOpt = rootSigs.TryFind(qualNameOfFile)
let rootSigs = Zmap.add qualNameOfFile sigFileType tcState.tcsRootSigs
if verbose then dprintf "ParsedInput.ImplFile, nm = %s, qualNameOfFile = %s, ?rootSigOpt = %b\n" filename qualNameOfFile.Text (Option.isSome rootSigOpt)
// Add the signature to the signature env (unless it had an explicit signature)
let ccuSigForFile = CombineCcuContentFragments m [sigFileType; tcState.tcsCcuSig]
// Open the prefixPath for fsi.exe
let tcEnv =
match prefixPathOpt with
| None -> tcEnv
| Some prefixPath ->
let m = qualNameOfFile.Range
TcOpenDecl tcSink tcGlobals amap m m tcEnv prefixPath
let tcState =
{ tcState with
tcsTcSigEnv=tcEnv
tcsTcImplEnv=tcState.tcsTcImplEnv
tcsRootSigs=rootSigs
tcsCreatesGeneratedProvidedTypes=tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes}
return (tcEnv, EmptyTopAttrs, None, ccuSigForFile), tcState
| ParsedInput.ImplFile (ParsedImplFileInput(_, _, qualNameOfFile, _, _, _, _) as file) ->
// Check if we've got an interface for this fragment
let rootSigOpt = tcState.tcsRootSigs.TryFind(qualNameOfFile)
// Check if we've already seen an implementation for this fragment
if Zset.contains qualNameOfFile rootImpls then
// Check if we've already seen an implementation for this fragment
if Zset.contains qualNameOfFile tcState.tcsRootImpls then
errorR(Error(FSComp.SR.buildImplementationAlreadyGiven(qualNameOfFile.Text), m))
let tcImplEnv = tcState.tcsTcImplEnv
let tcImplEnv = tcState.tcsTcImplEnv
// Typecheck the implementation file
let! topAttrs, implFile, tcEnvAtEnd, createsGeneratedProvidedTypes =
TypeCheckOneImplFile (tcGlobals, tcState.tcsNiceNameGen, amap, tcState.tcsCcu, checkForErrors, tcConfig.conditionalCompilationDefines, tcSink) tcImplEnv rootSigOpt file
// Typecheck the implementation file
let! topAttrs, implFile, _implFileHiddenType, tcEnvAtEnd, createsGeneratedProvidedTypes =
TypeCheckOneImplFile (tcGlobals, tcState.tcsNiceNameGen, amap, tcState.tcsCcu, checkForErrors, tcConfig.conditionalCompilationDefines, tcSink) tcImplEnv rootSigOpt file
let hadSig = Option.isSome rootSigOpt
let implFileSigType = SigTypeOfImplFile implFile
let hadSig = rootSigOpt.IsSome
let implFileSigType = SigTypeOfImplFile implFile
if verbose then dprintf "done TypeCheckOneImplFile...\n"
let rootImpls = Zset.add qualNameOfFile rootImpls
let rootImpls = Zset.add qualNameOfFile tcState.tcsRootImpls
// Only add it to the environment if it didn't have a signature
let m = qualNameOfFile.Range
// Only add it to the environment if it didn't have a signature
let m = qualNameOfFile.Range
// Add the implementation as to the implementation env
let tcImplEnv = AddLocalRootModuleOrNamespace TcResultsSink.NoSink tcGlobals amap m tcImplEnv implFileSigType
// Add the implementation as to the implementation env
let tcImplEnv = AddLocalRootModuleOrNamespace TcResultsSink.NoSink tcGlobals amap m tcImplEnv implFileSigType
// Add the implementation as to the signature env (unless it had an explicit signature)
let tcSigEnv =
if hadSig then tcState.tcsTcSigEnv
else AddLocalRootModuleOrNamespace TcResultsSink.NoSink tcGlobals amap m tcState.tcsTcSigEnv implFileSigType
// Add the implementation as to the signature env (unless it had an explicit signature)
let tcSigEnv =
if hadSig then tcState.tcsTcSigEnv
else AddLocalRootModuleOrNamespace TcResultsSink.NoSink tcGlobals amap m tcState.tcsTcSigEnv implFileSigType
// Open the prefixPath for fsi.exe (tcImplEnv)
let tcImplEnv =
match prefixPathOpt with
| Some prefixPath -> TcOpenDecl tcSink tcGlobals amap m m tcImplEnv prefixPath
| _ -> tcImplEnv
// Open the prefixPath for fsi.exe (tcSigEnv)
let tcSigEnv =
match prefixPathOpt with
| Some prefixPath when not hadSig -> TcOpenDecl tcSink tcGlobals amap m m tcSigEnv prefixPath
| _ -> tcSigEnv
let allImplementedSigModulTyp = CombineCcuContentFragments m [implFileSigType; allImplementedSigModulTyp]
// Add it to the CCU
let ccuType =
// The signature must be reestablished.
// [CHECK: Why? This seriously degraded performance]
NewCcuContents ILScopeRef.Local m tcState.tcsCcu.AssemblyName allImplementedSigModulTyp
if verbose then dprintf "done TypeCheckOneInputEventually...\n"
let topSigsAndImpls = RootSigsAndImpls(rootSigs, rootImpls, allSigModulTyp, allImplementedSigModulTyp)
let res = (topAttrs, Some implFile, tcEnvAtEnd, tcSigEnv, tcImplEnv, topSigsAndImpls, ccuType, createsGeneratedProvidedTypes)
return res }
// Open the prefixPath for fsi.exe (tcImplEnv)
let tcImplEnv =
match prefixPathOpt with
| Some prefixPath -> TcOpenDecl tcSink tcGlobals amap m m tcImplEnv prefixPath
| _ -> tcImplEnv
// Open the prefixPath for fsi.exe (tcSigEnv)
let tcSigEnv =
match prefixPathOpt with
| Some prefixPath when not hadSig -> TcOpenDecl tcSink tcGlobals amap m m tcSigEnv prefixPath
| _ -> tcSigEnv
let ccuSig = CombineCcuContentFragments m [implFileSigType; tcState.tcsCcuSig ]
let ccuSigForFile = CombineCcuContentFragments m [implFileSigType; tcState.tcsCcuSig]
let tcState =
{ tcState with
tcsTcSigEnv=tcSigEnv
tcsTcImplEnv=tcImplEnv
tcsRootImpls=rootImpls
tcsCcuSig=ccuSig
tcsCreatesGeneratedProvidedTypes=tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes }
return (tcEnvAtEnd, topAttrs, Some implFile, ccuSigForFile), tcState
return (tcEnvAtEnd, topAttrs, implFiles),
{ tcState with
tcsCcuType=ccuType
tcsTcSigEnv=tcSigEnv
tcsTcImplEnv=tcImplEnv
tcsCreatesGeneratedProvidedTypes=tcState.tcsCreatesGeneratedProvidedTypes || createsGeneratedProvidedTypes
tcsRootSigsAndImpls = topSigsAndImpls }
with e ->
errorRecovery e range0
return (tcState.TcEnvFromSignatures, EmptyTopAttrs, None), tcState
}
with e ->
errorRecovery e range0
return (tcState.TcEnvFromSignatures, EmptyTopAttrs, None, tcState.tcsCcuSig), tcState
}
/// Typecheck a single file (or interactive entry into F# Interactive)
let TypeCheckOneInput (ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt) tcState inp =
......@@ -5523,19 +5524,12 @@ let TypeCheckOneInput (ctok, checkForErrors, tcConfig, tcImports, tcGlobals, pre
/// Finish checking multiple files (or one interactive entry into F# Interactive)
let TypeCheckMultipleInputsFinish(results, tcState: TcState) =
let tcEnvsAtEndFile, topAttrs, implFiles = List.unzip3 results
let tcEnvsAtEndFile, topAttrs, implFiles, ccuSigsForFiles = List.unzip4 results
let topAttrs = List.foldBack CombineTopAttrs topAttrs EmptyTopAttrs
let implFiles = List.choose id implFiles
// This is the environment required by fsi.exe when incrementally adding definitions
let tcEnvAtEndOfLastFile = (match tcEnvsAtEndFile with h :: _ -> h | _ -> tcState.TcEnvFromSignatures)
(tcEnvAtEndOfLastFile, topAttrs, implFiles), tcState
/// Check multiple files (or one interactive entry into F# Interactive)
let TypeCheckMultipleInputs (ctok, checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcState, inputs) =
let results, tcState = (tcState, inputs) ||> List.mapFold (TypeCheckOneInput (ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt))
TypeCheckMultipleInputsFinish(results, tcState)
(tcEnvAtEndOfLastFile, topAttrs, implFiles, ccuSigsForFiles), tcState
let TypeCheckOneInputAndFinishEventually(checkForErrors, tcConfig: TcConfig, tcImports, tcGlobals, prefixPathOpt, tcSink, tcState, input) =
eventually {
......@@ -5545,18 +5539,18 @@ let TypeCheckOneInputAndFinishEventually(checkForErrors, tcConfig: TcConfig, tcI
let TypeCheckClosedInputSetFinish (declaredImpls: TypedImplFile list, tcState) =
// Publish the latest contents to the CCU
tcState.tcsCcu.Deref.Contents <- tcState.tcsCcuType
tcState.tcsCcu.Deref.Contents <- NewCcuContents ILScopeRef.Local range0 tcState.tcsCcu.AssemblyName tcState.tcsCcuSig
// Check all interfaces have implementations
let (RootSigsAndImpls(rootSigs, rootImpls, _, _)) = tcState.tcsRootSigsAndImpls
rootSigs |> Zmap.iter (fun qualNameOfFile _ ->
if not (Zset.contains qualNameOfFile rootImpls) then
tcState.tcsRootSigs |> Zmap.iter (fun qualNameOfFile _ ->
if not (Zset.contains qualNameOfFile tcState.tcsRootImpls) then
errorR(Error(FSComp.SR.buildSignatureWithoutImplementation(qualNameOfFile.Text), qualNameOfFile.Range)))
tcState, declaredImpls
let TypeCheckClosedInputSet (ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcState, inputs) =
// tcEnvAtEndOfLastFile is the environment required by fsi.exe when incrementally adding definitions
let (tcEnvAtEndOfLastFile, topAttrs, implFiles), tcState = TypeCheckMultipleInputs (ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt, tcState, inputs)
let results, tcState = (tcState, inputs) ||> List.mapFold (TypeCheckOneInput (ctok, checkForErrors, tcConfig, tcImports, tcGlobals, prefixPathOpt))
let (tcEnvAtEndOfLastFile, topAttrs, implFiles, _), tcState = TypeCheckMultipleInputsFinish(results, tcState)
let tcState, declaredImpls = TypeCheckClosedInputSetFinish (implFiles, tcState)
tcState, topAttrs, declaredImpls, tcEnvAtEndOfLastFile
......@@ -704,8 +704,10 @@ type TcState =
/// Get the typing environment implied by the set of implementation files checked so far
member TcEnvFromImpls: TcEnv
/// The inferred contents of the assembly, containing the signatures of all implemented files.
member PartialAssemblySignature: ModuleOrNamespaceType
/// The inferred contents of the assembly, containing the signatures of all files.
// a.fsi + b.fsi + c.fsi (after checking implementation file for c.fs)
member CcuSig: ModuleOrNamespaceType
member NextStateAfterIncrementalFragment: TcEnv -> TcState
......@@ -718,10 +720,10 @@ val GetInitialTcState:
/// Check one input, returned as an Eventually computation
val TypeCheckOneInputEventually :
checkForErrors:(unit -> bool) * TcConfig * TcImports * TcGlobals * Ast.LongIdent option * NameResolution.TcResultsSink * TcState * Ast.ParsedInput
-> Eventually<(TcEnv * TopAttribs * TypedImplFile option) * TcState>
-> Eventually<(TcEnv * TopAttribs * TypedImplFile option * ModuleOrNamespaceType) * TcState>
/// Finish the checking of multiple inputs
val TypeCheckMultipleInputsFinish: (TcEnv * TopAttribs * 'T option) list * TcState -> (TcEnv * TopAttribs * 'T list) * TcState
val TypeCheckMultipleInputsFinish: (TcEnv * TopAttribs * 'T option * 'U) list * TcState -> (TcEnv * TopAttribs * 'T list * 'U list) * TcState
/// Finish the checking of a closed set of inputs
val TypeCheckClosedInputSetFinish: TypedImplFile list * TcState -> TcState * TypedImplFile list
......@@ -732,7 +734,7 @@ val TypeCheckClosedInputSet: CompilationThreadToken * checkForErrors: (unit -> b
/// Check a single input and finish the checking
val TypeCheckOneInputAndFinishEventually :
checkForErrors: (unit -> bool) * TcConfig * TcImports * TcGlobals * Ast.LongIdent option * NameResolution.TcResultsSink * TcState * Ast.ParsedInput
-> Eventually<(TcEnv * TopAttribs * TypedImplFile list) * TcState>
-> Eventually<(TcEnv * TopAttribs * TypedImplFile list * ModuleOrNamespaceType list) * TcState>
/// Indicates if we should report a warning
val ReportWarning: FSharpErrorSeverityOptions -> PhasedDiagnostic -> bool
......
......@@ -415,7 +415,7 @@ namespace Microsoft.FSharp.Collections
let filter predicate list = Microsoft.FSharp.Primitives.Basics.List.filter predicate list
[<CompiledName("Except")>]
let except itemsToExclude list =
let except (itemsToExclude: seq<'T>) list =
checkNonNull "itemsToExclude" itemsToExclude
match list with
| [] -> list
......
......@@ -218,7 +218,7 @@ let accTycons cenv env tycons = List.iter (accTycon cenv env) tycons
let rec accModuleOrNamespaceExpr cenv env x =
match x with
| ModuleOrNamespaceExprWithSig(_mty,def,_m) -> accModuleOrNamespaceDef cenv env def
| ModuleOrNamespaceExprWithSig(_mty, def, _m) -> accModuleOrNamespaceDef cenv env def
and accModuleOrNamespaceDefs cenv env x = List.iter (accModuleOrNamespaceDef cenv env) x
......
......@@ -970,7 +970,7 @@ and AddBindingsForModuleDef allocVal cloc eenv x =
allocVal cloc bind.Var eenv
| TMDefDo _ ->
eenv
| TMAbstract(ModuleOrNamespaceExprWithSig(mtyp,_,_)) ->
| TMAbstract(ModuleOrNamespaceExprWithSig(mtyp, _, _)) ->
AddBindingsForLocalModuleType allocVal cloc eenv mtyp
| TMDefs(mdefs) ->
AddBindingsForModuleDefs allocVal cloc eenv mdefs
......@@ -1001,8 +1001,7 @@ let AddIncrementalLocalAssemblyFragmentToIlxGenEnv (amap:ImportMap, isIncrementa
let cloc = { cloc with clocTopImplQualifiedName = qname.Text }
if isIncrementalFragment then
match mexpr with
| ModuleOrNamespaceExprWithSig(_,mdef,_) -> AddBindingsForModuleDef allocVal cloc eenv mdef
(* | ModuleOrNamespaceExprWithSig(mtyp,_,m) -> error(Error("don't expect inner defs to have a constraint",m)) *)
| ModuleOrNamespaceExprWithSig(_, mdef, _) -> AddBindingsForModuleDef allocVal cloc eenv mdef
else
AddBindingsForLocalModuleType allocVal cloc eenv mexpr.Type)
......@@ -5782,7 +5781,7 @@ and GenTypeDefForCompLoc (cenv, eenv, mgbuf: AssemblyBuilder, cloc, hidden, attr
and GenModuleExpr cenv cgbuf qname lazyInitInfo eenv x =
let (ModuleOrNamespaceExprWithSig(mty,def,_)) = x
let (ModuleOrNamespaceExprWithSig(mty, def, _)) = x
// REVIEW: the scopeMarks are used for any shadow locals we create for the module bindings
// We use one scope for all the bindings in the module, which makes them all appear with their "default" values
// rather than incrementally as we step through the initializations in the module. This is a little unfortunate
......
......@@ -1249,9 +1249,9 @@ module Pass4_RewriteAssembly =
and TransValBindings penv z binds = List.mapFold (TransValBinding penv) z binds
and TransModuleExpr penv z x =
match x with
| ModuleOrNamespaceExprWithSig(mty,def,m) ->
| ModuleOrNamespaceExprWithSig(mty, def, m) ->
let def,z = TransModuleDef penv z def
ModuleOrNamespaceExprWithSig(mty,def,m),z
ModuleOrNamespaceExprWithSig(mty, def, m),z
and TransModuleDefs penv z x = List.mapFold (TransModuleDef penv) z x
and TransModuleDef penv (z: RewriteState) x : ModuleOrNamespaceExpr * RewriteState =
......
......@@ -1824,11 +1824,11 @@ module private InferredSigPrinting =
| TMDefLet _ -> true
| TMDefDo _ -> true
| TMDefs defs -> defs |> List.exists isConcreteNamespace
| TMAbstract(ModuleOrNamespaceExprWithSig(_,def,_)) -> isConcreteNamespace def
| TMAbstract(ModuleOrNamespaceExprWithSig(_, def, _)) -> isConcreteNamespace def
let rec imexprLP denv (ModuleOrNamespaceExprWithSig(_,def,_)) = imdefL denv def
let rec imexprLP denv (ModuleOrNamespaceExprWithSig(_, def, _)) = imdefL denv def
and imexprL denv (ModuleOrNamespaceExprWithSig(mty,def,m)) = imexprLP denv (ModuleOrNamespaceExprWithSig(mty,def,m))
and imexprL denv (ModuleOrNamespaceExprWithSig(mty, def, m)) = imexprLP denv (ModuleOrNamespaceExprWithSig(mty, def, m))
and imdefsL denv x = aboveListL (x |> List.map (imdefL denv))
......
......@@ -3154,7 +3154,7 @@ and OptimizeModuleDefs cenv (env, bindInfosColl) defs =
let defs, minfos = List.unzip defs
(defs, UnionOptimizationInfos minfos), (env, bindInfosColl)
and OptimizeImplFileInternal cenv env isIncrementalFragment hidden (TImplFile(qname, pragmas, (ModuleOrNamespaceExprWithSig(mty, _, _) as mexpr), hasExplicitEntryPoint, isScript)) =
and OptimizeImplFileInternal cenv env isIncrementalFragment hidden (TImplFile(qname, pragmas, mexpr, hasExplicitEntryPoint, isScript)) =
let env, mexpr', minfo =
match mexpr with
// FSI: FSI compiles everything as if you're typing incrementally into one module
......@@ -3170,7 +3170,7 @@ and OptimizeImplFileInternal cenv env isIncrementalFragment hidden (TImplFile(qn
let env = { env with localExternalVals=env.localExternalVals.MarkAsCollapsible() } // take the chance to flatten to a dictionary
env, mexpr', minfo
let hidden = ComputeHidingInfoAtAssemblyBoundary mty hidden
let hidden = ComputeHidingInfoAtAssemblyBoundary mexpr.Type hidden
let minfo = AbstractLazyModulInfoByHiding true hidden minfo
env, TImplFile(qname, pragmas, mexpr', hasExplicitEntryPoint, isScript), minfo, hidden
......
......@@ -1657,7 +1657,7 @@ let CheckEntityDefns cenv env tycons =
let rec CheckModuleExpr cenv env x =
match x with
| ModuleOrNamespaceExprWithSig(mty,def,_) ->
| ModuleOrNamespaceExprWithSig(mty, def, _) ->
let (rpi,mhi) = ComputeRemappingFromImplementationToSignature cenv.g def mty
let env = { env with sigToImplRemapInfo = (mkRepackageRemapping rpi,mhi) :: env.sigToImplRemapInfo }
CheckDefnInModule cenv env def
......
......@@ -3692,6 +3692,7 @@ let wrapModuleOrNamespaceExprInNamespace (id :Ident) cpath mexpr =
// cleanup: make this a property
let SigTypeOfImplFile (TImplFile(_, _, mexpr, _, _)) = mexpr.Type
//--------------------------------------------------------------------------
// Data structures representing what gets hidden and what gets remapped (i.e. renamed or alpha-converted)
// when a module signature is applied to a module.
......@@ -5087,12 +5088,12 @@ and allValsOfModDef mdef =
| TMAbstract(ModuleOrNamespaceExprWithSig(mty, _, _)) ->
yield! allValsOfModuleOrNamespaceTy mty }
and remapAndBindModExpr g compgen tmenv (ModuleOrNamespaceExprWithSig(mty, mdef, m)) =
and remapAndBindModuleOrNamespaceExprWithSig g compgen tmenv (ModuleOrNamespaceExprWithSig(mty, mdef, m)) =
let mdef = copyAndRemapModDef g compgen tmenv mdef
let mty, tmenv = copyAndRemapAndBindModTy g compgen tmenv mty
ModuleOrNamespaceExprWithSig(mty, mdef, m), tmenv
and remapModExpr g compgen tmenv (ModuleOrNamespaceExprWithSig(mty, mdef, m)) =
and remapModuleOrNamespaceExprWithSig g compgen tmenv (ModuleOrNamespaceExprWithSig(mty, mdef, m)) =
let mdef = copyAndRemapModDef g compgen tmenv mdef
let mty = remapModTy g compgen tmenv mty
ModuleOrNamespaceExprWithSig(mty, mdef, m)
......@@ -5124,7 +5125,7 @@ and remapAndRenameModDef g compgen tmenv mdef =
let defs = remapAndRenameModDefs g compgen tmenv defs
TMDefs defs
| TMAbstract mexpr ->
let mexpr = remapModExpr g compgen tmenv mexpr
let mexpr = remapModuleOrNamespaceExprWithSig g compgen tmenv mexpr
TMAbstract mexpr
and remapAndRenameModBind g compgen tmenv x =
......@@ -5139,7 +5140,7 @@ and remapAndRenameModBind g compgen tmenv x =
ModuleOrNamespaceBinding.Module(mspec, def)
and remapImplFile g compgen tmenv mv =
mapAccImplFile (remapAndBindModExpr g compgen) tmenv mv
mapAccImplFile (remapAndBindModuleOrNamespaceExprWithSig g compgen) tmenv mv
let copyModuleOrNamespaceType g compgen mtyp = copyAndRemapAndBindModTy g compgen Remap.Empty mtyp |> fst
let copyExpr g compgen e = remapExpr g compgen Remap.Empty e
......@@ -7709,7 +7710,6 @@ and rewriteObjExprInterfaceImpl env (ty, overrides) =
and rewriteModuleOrNamespaceExpr env x =
match x with
(* | ModuleOrNamespaceExprWithSig(mty, e, m) -> ModuleOrNamespaceExprWithSig(mty, rewriteModuleOrNamespaceExpr env e, m) *)
| ModuleOrNamespaceExprWithSig(mty, def, m) -> ModuleOrNamespaceExprWithSig(mty, rewriteModuleOrNamespaceDef env def, m)
and rewriteModuleOrNamespaceDefs env x = List.map (rewriteModuleOrNamespaceDef env) x
......
......@@ -17166,7 +17166,7 @@ let TypeCheckOneImplFile
let implFile = TImplFile(qualNameOfFile, scopedPragmas, implFileExprAfterSig, hasExplicitEntryPoint, isScript)
return (topAttrs, implFile, envAtEnd, cenv.createsGeneratedProvidedTypes)
return (topAttrs, implFile, implFileTypePriorToSig, envAtEnd, cenv.createsGeneratedProvidedTypes)
}
......
......@@ -43,7 +43,7 @@ val TypeCheckOneImplFile :
-> TcEnv
-> Tast.ModuleOrNamespaceType option
-> ParsedImplFileInput
-> Eventually<TopAttribs * Tast.TypedImplFile * TcEnv * bool>
-> Eventually<TopAttribs * Tast.TypedImplFile * ModuleOrNamespaceType * TcEnv * bool>
val TypeCheckOneSigFile :
TcGlobals * NiceNameGenerator * ImportMap * CcuThunk * (unit -> bool) * ConditionalDefines * NameResolution.TcResultsSink
......
......@@ -1162,7 +1162,7 @@ type internal FsiDynamicCompiler
// Find all new declarations the EvaluationListener
try
let contents = FSharpAssemblyContents(tcGlobals, tcState.Ccu, tcImports, declaredImpls)
let contents = FSharpAssemblyContents(tcGlobals, tcState.Ccu, Some tcState.CcuSig, tcImports, declaredImpls)
let contentFile = contents.ImplementationFiles.[0]
// Skip the "FSI_NNNN"
match contentFile.Declarations with
......@@ -1177,16 +1177,16 @@ type internal FsiDynamicCompiler
| Item.Value vref ->
let optValue = newState.ilxGenerator.LookupGeneratedValue(valuePrinter.GetEvaluationContext(newState.emEnv), vref.Deref)
match optValue with
| Some (res, typ) -> Some(FsiValue(res, typ, FSharpType(tcGlobals, newState.tcState.Ccu, newState.tcImports, vref.Type)))
| Some (res, typ) -> Some(FsiValue(res, typ, FSharpType(tcGlobals, newState.tcState.Ccu, newState.tcState.CcuSig, newState.tcImports, vref.Type)))
| None -> None
| _ -> None
let symbol = FSharpSymbol.Create(newState.tcGlobals, newState.tcState.Ccu, newState.tcImports, v.Item)
let symbol = FSharpSymbol.Create(newState.tcGlobals, newState.tcState.Ccu, newState.tcState.CcuSig, newState.tcImports, v.Item)
let symbolUse = FSharpSymbolUse(tcGlobals, newState.tcState.TcEnvFromImpls.DisplayEnv, symbol, ItemOccurence.Binding, v.DeclarationLocation)
fsi.TriggerEvaluation (fsiValueOpt, symbolUse, decl)
| FSharpImplementationFileDeclaration.Entity (e,_) ->
// Report a top-level module or namespace definition
let symbol = FSharpSymbol.Create(newState.tcGlobals, newState.tcState.Ccu, newState.tcImports, e.Item)
let symbol = FSharpSymbol.Create(newState.tcGlobals, newState.tcState.Ccu, newState.tcState.CcuSig, newState.tcImports, e.Item)
let symbolUse = FSharpSymbolUse(tcGlobals, newState.tcState.TcEnvFromImpls.DisplayEnv, symbol, ItemOccurence.Binding, e.DeclarationLocation)
fsi.TriggerEvaluation (None, symbolUse, decl)
| FSharpImplementationFileDeclaration.InitAction _ ->
......@@ -1224,7 +1224,7 @@ type internal FsiDynamicCompiler
//
let optValue = istate.ilxGenerator.LookupGeneratedValue(valuePrinter.GetEvaluationContext(istate.emEnv), vref.Deref);
match optValue with
| Some (res, typ) -> istate, Completed(Some(FsiValue(res, typ, FSharpType(tcGlobals, istate.tcState.Ccu, istate.tcImports, vref.Type))))
| Some (res, typ) -> istate, Completed(Some(FsiValue(res, typ, FSharpType(tcGlobals, istate.tcState.Ccu, istate.tcState.CcuSig, istate.tcImports, vref.Type))))
| _ -> istate, Completed None
// Return the interactive state.
......@@ -1349,7 +1349,7 @@ type internal FsiDynamicCompiler
}
member __.CurrentPartialAssemblySignature(istate) =
FSharpAssemblySignature(istate.tcGlobals, istate.tcState.Ccu, istate.tcImports, None, istate.tcState.PartialAssemblySignature)
FSharpAssemblySignature(istate.tcGlobals, istate.tcState.Ccu, istate.tcState.CcuSig, istate.tcImports, None, istate.tcState.CcuSig)
member __.FormatValue(obj:obj, objTy) =
valuePrinter.FormatValue(obj, objTy)
......
......@@ -1037,7 +1037,9 @@ type TypeCheckAccumulator =
topAttribs:TopAttribs option
/// Result of checking most recent file, if any
lastestTypedImplFile:TypedImplFile option
latestImplFile:TypedImplFile option
latestCcuSigForFile: ModuleOrNamespaceType option
tcDependencyFiles: string list
......@@ -1126,7 +1128,8 @@ type PartialCheckResults =
TcDependencyFiles: string list
TopAttribs: TopAttribs option
TimeStamp: DateTime
LatestImplementationFile: TypedImplFile option }
LatestImplementationFile: TypedImplFile option
LastestCcuSigForFile: ModuleOrNamespaceType option }
member x.TcErrors = Array.concat (List.rev x.TcErrorsRev)
member x.TcSymbolUses = List.rev x.TcSymbolUsesRev
......@@ -1144,7 +1147,8 @@ type PartialCheckResults =
TcDependencyFiles = tcAcc.tcDependencyFiles
TopAttribs = tcAcc.topAttribs
TimeStamp = timestamp
LatestImplementationFile = tcAcc.lastestTypedImplFile }
LatestImplementationFile = tcAcc.latestImplFile
LastestCcuSigForFile = tcAcc.latestCcuSigForFile }
[<AutoOpen>]
......@@ -1350,7 +1354,8 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput
tcSymbolUsesRev=[]
tcOpenDeclarationsRev=[]
topAttribs=None
lastestTypedImplFile=None
latestImplFile=None
latestCcuSigForFile=None
tcDependencyFiles=basicDependencies
tcErrorsRev = [ initialErrors ] }
return tcAcc }
......@@ -1373,7 +1378,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput
let sink = TcResultsSinkImpl(tcAcc.tcGlobals)
let hadParseErrors = not (Array.isEmpty parseErrors)
let! (tcEnvAtEndOfFile, topAttribs, lastestTypedImplFile), tcState =
let! (tcEnvAtEndOfFile, topAttribs, implFile, ccuSigForFile), tcState =
TypeCheckOneInputEventually
((fun () -> hadParseErrors || errorLogger.ErrorCount > 0),
tcConfig, tcAcc.tcImports,
......@@ -1383,7 +1388,7 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput
tcAcc.tcState, input)
/// Only keep the typed interface files when doing a "full" build for fsc.exe, otherwise just throw them away
let lastestTypedImplFile = if keepAssemblyContents then lastestTypedImplFile else None
let implFile = if keepAssemblyContents then implFile else None
let tcResolutions = if keepAllBackgroundResolutions then sink.GetResolutions() else TcResolutions.Empty
let tcEnvAtEndOfFile = (if keepAllBackgroundResolutions then tcEnvAtEndOfFile else tcState.TcEnvFromImpls)
let tcSymbolUses = sink.GetSymbolUses()
......@@ -1395,7 +1400,8 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput
return {tcAcc with tcState=tcState
tcEnvAtEndOfFile=tcEnvAtEndOfFile
topAttribs=Some topAttribs
lastestTypedImplFile=lastestTypedImplFile
latestImplFile=implFile
latestCcuSigForFile=Some ccuSigForFile
tcResolutionsRev=tcResolutions :: tcAcc.tcResolutionsRev
tcSymbolUsesRev=tcSymbolUses :: tcAcc.tcSymbolUsesRev
tcOpenDeclarationsRev = sink.GetOpenDeclarations() :: tcAcc.tcOpenDeclarationsRev
......@@ -1437,16 +1443,16 @@ type IncrementalBuilder(tcGlobals, frameworkTcImports, nonFrameworkAssemblyInput
let finalAcc = tcStates.[tcStates.Length-1]
// Finish the checking
let (_tcEnvAtEndOfLastFile, topAttrs, mimpls), tcState =
let results = tcStates |> List.ofArray |> List.map (fun acc-> acc.tcEnvAtEndOfFile, defaultArg acc.topAttribs EmptyTopAttrs, acc.lastestTypedImplFile)
let (_tcEnvAtEndOfLastFile, topAttrs, mimpls, _), tcState =
let results = tcStates |> List.ofArray |> List.map (fun acc-> acc.tcEnvAtEndOfFile, defaultArg acc.topAttribs EmptyTopAttrs, acc.latestImplFile, acc.latestCcuSigForFile)
TypeCheckMultipleInputsFinish (results, finalAcc.tcState)
let ilAssemRef, tcAssemblyDataOpt, tcAssemblyExprOpt =
try
// TypeCheckClosedInputSetFinish fills in tcState.Ccu but in incremental scenarios we don't want this,
// so we make this temporary here
let oldContents = tcState.Ccu.Deref.Contents
try
// TypeCheckClosedInputSetFinish fills in tcState.Ccu but in incremental scenarios we don't want this,
// so we make this temporary here
let oldContents = tcState.Ccu.Deref.Contents
try
let tcState, tcAssemblyExpr = TypeCheckClosedInputSetFinish (mimpls, tcState)
// Compute the identity of the generated assembly based on attributes, options etc.
......
......@@ -64,7 +64,10 @@ type internal PartialCheckResults =
/// Represents latest complete typechecked implementation file, including its typechecked signature if any.
/// Empty for a signature file.
LatestImplementationFile: TypedImplFile option }
LatestImplementationFile: TypedImplFile option
/// Represents latest inferred signature contents.
LastestCcuSigForFile: ModuleOrNamespaceType option}
member TcErrors: (PhasedDiagnostic * FSharpErrorSeverity)[]
......
此差异已折叠。
......@@ -268,7 +268,7 @@ module FSharpExprConvert =
| DT_REF -> None
| _ -> None
let (|TTypeConvOp|_|) (cenv:Impl.cenv) ty =
let (|TTypeConvOp|_|) (cenv:SymbolEnv) ty =
let g = cenv.g
match ty with
| TType_app (tcref,_) ->
......@@ -291,14 +291,14 @@ module FSharpExprConvert =
let ConvType cenv typ = FSharpType(cenv, typ)
let ConvTypes cenv typs = List.map (ConvType cenv) typs
let ConvILTypeRefApp (cenv:Impl.cenv) m tref tyargs =
let ConvILTypeRefApp (cenv:SymbolEnv) m tref tyargs =
let tcref = Import.ImportILTypeRef cenv.amap m tref
ConvType cenv (mkAppTy tcref tyargs)
let ConvUnionCaseRef cenv (ucref:UnionCaseRef) = FSharpUnionCase(cenv, ucref)
let ConvRecdFieldRef cenv (rfref:RecdFieldRef) = FSharpField(cenv, rfref )
let rec exprOfExprAddr (cenv:Impl.cenv) expr =
let rec exprOfExprAddr (cenv:SymbolEnv) expr =
match expr with
| Expr.Op(op, tyargs, args, m) ->
match op, args, tyargs with
......@@ -323,7 +323,7 @@ module FSharpExprConvert =
let Mk2 cenv (orig:Expr) e = FSharpExpr(cenv, None, e, orig.Range, tyOfExpr cenv.g orig)
let rec ConvLValueExpr (cenv:Impl.cenv) env expr = ConvExpr cenv env (exprOfExprAddr cenv expr)
let rec ConvLValueExpr (cenv:SymbolEnv) env expr = ConvExpr cenv env (exprOfExprAddr cenv expr)
and ConvExpr cenv env expr =
Mk2 cenv expr (ConvExprPrim cenv env expr)
......@@ -391,7 +391,7 @@ module FSharpExprConvert =
/// A nasty function copied from creflect.fs. Made nastier by taking a continuation to process the
/// arguments to the call in a tail-recursive fashion.
and ConvModuleValueOrMemberUseLinear (cenv:Impl.cenv) env (expr:Expr, vref, vFlags, tyargs, curriedArgs) contf =
and ConvModuleValueOrMemberUseLinear (cenv:SymbolEnv) env (expr:Expr, vref, vFlags, tyargs, curriedArgs) contf =
let m = expr.Range
let (numEnclTypeArgs, _, isNewObj, _valUseFlags, _isSelfInit, takesInstanceArg, _isPropGet, _isPropSet) =
......@@ -462,7 +462,7 @@ module FSharpExprConvert =
// tailcall
ConvObjectModelCallLinear cenv env (false, v, [], tyargs, List.concat untupledCurriedArgs) contf2
and ConvExprPrim (cenv:Impl.cenv) (env:ExprTranslationEnv) expr =
and ConvExprPrim (cenv:SymbolEnv) (env:ExprTranslationEnv) expr =
// Eliminate integer 'for' loops
let expr = DetectAndOptimizeForExpression cenv.g OptimizeIntRangesOnly expr
......@@ -854,7 +854,7 @@ module FSharpExprConvert =
let envinner = env.BindVal v
Some(vR, rhsR), envinner
and ConvILCall (cenv:Impl.cenv) env (isNewObj, valUseFlags, ilMethRef, enclTypeArgs, methTypeArgs, callArgs, m) =
and ConvILCall (cenv:SymbolEnv) env (isNewObj, valUseFlags, ilMethRef, enclTypeArgs, methTypeArgs, callArgs, m) =
let isNewObj = (isNewObj || (match valUseFlags with CtorValUsedAsSuperInit | CtorValUsedAsSelfInit -> true | _ -> false))
let methName = ilMethRef.Name
let isPropGet = methName.StartsWith("get_", System.StringComparison.Ordinal)
......@@ -1210,9 +1210,9 @@ module FSharpExprConvert =
/// The contents of the F# assembly as provided through the compiler API
type FSharpAssemblyContents(cenv: Impl.cenv, mimpls: TypedImplFile list) =
type FSharpAssemblyContents(cenv: SymbolEnv, mimpls: TypedImplFile list) =
new (g, thisCcu, tcImports, mimpls) = FSharpAssemblyContents(Impl.cenv(g, thisCcu, tcImports), mimpls)
new (g, thisCcu, thisCcuType, tcImports, mimpls) = FSharpAssemblyContents(SymbolEnv(g, thisCcu, thisCcuType, tcImports), mimpls)
member __.ImplementationFiles =
[ for mimpl in mimpls -> FSharpImplementationFileContents(cenv, mimpl)]
......@@ -1223,7 +1223,7 @@ and FSharpImplementationFileDeclaration =
| InitAction of FSharpExpr
and FSharpImplementationFileContents(cenv, mimpl) =
let (TImplFile(qname, _pragmas, ModuleOrNamespaceExprWithSig(_mty, mdef, _), hasExplicitEntryPoint, isScript)) = mimpl
let (TImplFile(qname, _pragmas, ModuleOrNamespaceExprWithSig(_, mdef, _), hasExplicitEntryPoint, isScript)) = mimpl
let rec getDecls2 (ModuleOrNamespaceExprWithSig(_mty, def, _m)) = getDecls def
and getBind (bind: Binding) =
let v = bind.Var
......
......@@ -12,14 +12,14 @@ open Microsoft.FSharp.Compiler.CompileOps
/// Represents the definitional contents of an assembly, as seen by the F# language
type public FSharpAssemblyContents =
internal new : tcGlobals: TcGlobals * thisCcu: CcuThunk * tcImports: TcImports * mimpls: TypedImplFile list -> FSharpAssemblyContents
internal new : tcGlobals: TcGlobals * thisCcu: CcuThunk * thisCcuType: ModuleOrNamespaceType option * tcImports: TcImports * mimpls: TypedImplFile list -> FSharpAssemblyContents
/// The contents of the implementation files in the assembly
member ImplementationFiles: FSharpImplementationFileContents list
/// Represents the definitional contents of a single file or fragment in an assembly, as seen by the F# language
and [<Class>] public FSharpImplementationFileContents =
internal new : cenv: Impl.cenv * mimpl: TypedImplFile -> FSharpImplementationFileContents
internal new : cenv: SymbolEnv * mimpl: TypedImplFile -> FSharpImplementationFileContents
/// The qualified name acts to fully-qualify module specifications and implementations
member QualifiedName: string
......
此差异已折叠。
......@@ -13,11 +13,10 @@ open Microsoft.FSharp.Compiler.TcGlobals
open Microsoft.FSharp.Compiler.NameResolution
// Implementation details used by other code in the compiler
module internal Impl =
type internal cenv =
new : TcGlobals * thisCcu:CcuThunk * tcImports: TcImports -> cenv
member amap: Import.ImportMap
member g: TcGlobals
type internal SymbolEnv =
new : TcGlobals * thisCcu:CcuThunk * thisCcuTyp: ModuleOrNamespaceType option * tcImports: TcImports -> SymbolEnv
member amap: Import.ImportMap
member g: TcGlobals
/// Indicates the accessibility of a symbol, as seen by the F# language
type public FSharpAccessibility =
......@@ -52,7 +51,7 @@ type [<Class>] public FSharpDisplayContext =
/// or FSharpActivePatternCase.
type [<Class>] public FSharpSymbol =
/// Internal use only.
static member internal Create : g:TcGlobals * thisCcu: CcuThunk * tcImports: TcImports * item:NameResolution.Item -> FSharpSymbol
static member internal Create : g:TcGlobals * thisCcu: CcuThunk * thisCcuTyp: ModuleOrNamespaceType * tcImports: TcImports * item:NameResolution.Item -> FSharpSymbol
/// Computes if the symbol is accessible for the given accessibility rights
member IsAccessible: FSharpAccessibilityRights -> bool
......@@ -121,7 +120,7 @@ and [<Class>] public FSharpAssembly =
/// Represents an inferred signature of part of an assembly as seen by the F# language
and [<Class>] public FSharpAssemblySignature =
internal new : tcGlobals: TcGlobals * thisCcu: CcuThunk * tcImports: TcImports * topAttribs: TypeChecker.TopAttribs option * contents: ModuleOrNamespaceType -> FSharpAssemblySignature
internal new : tcGlobals: TcGlobals * thisCcu: CcuThunk * thisCcuTyp: ModuleOrNamespaceType * tcImports: TcImports * topAttribs: TypeChecker.TopAttribs option * contents: ModuleOrNamespaceType -> FSharpAssemblySignature
/// The (non-nested) module and type definitions in this signature
member Entities: IList<FSharpEntity>
......@@ -138,11 +137,11 @@ and [<Class>] public FSharpAssemblySignature =
and [<Class>] public FSharpEntity =
inherit FSharpSymbol
internal new : Impl.cenv * EntityRef -> FSharpEntity
// /// Return the FSharpEntity corresponding to a .NET type
// static member FromType : System.Type -> FSharpEntity
internal new : SymbolEnv * EntityRef -> FSharpEntity
/// Get the enclosing entity for the definition
member DeclaringEntity : FSharpEntity option
/// Get the name of the type or module, possibly with `n mangling
member LogicalName: string
......@@ -344,7 +343,7 @@ and [<Class>] public FSharpAbstractParameter =
/// Represents the signature of an abstract slot of a class or interface
and [<Class>] public FSharpAbstractSignature =
internal new : Impl.cenv * SlotSig -> FSharpAbstractSignature
internal new : SymbolEnv * SlotSig -> FSharpAbstractSignature
/// Get the arguments of the abstract slot
member AbstractArguments : IList<IList<FSharpAbstractParameter>>
......@@ -367,7 +366,7 @@ and [<Class>] public FSharpAbstractSignature =
/// A subtype of FSharpSymbol that represents a union case as seen by the F# language
and [<Class>] public FSharpUnionCase =
inherit FSharpSymbol
internal new : Impl.cenv * UnionCaseRef -> FSharpUnionCase
internal new : SymbolEnv * UnionCaseRef -> FSharpUnionCase
/// Get the name of the union case
member Name: string
......@@ -405,8 +404,8 @@ and [<Class>] public FSharpUnionCase =
and [<Class>] public FSharpField =
inherit FSharpSymbol
internal new : Impl.cenv * RecdFieldRef -> FSharpField
internal new : Impl.cenv * UnionCaseRef * int -> FSharpField
internal new : SymbolEnv * RecdFieldRef -> FSharpField
internal new : SymbolEnv * UnionCaseRef * int -> FSharpField
/// Get the declaring entity of this field
member DeclaringEntity: FSharpEntity
......@@ -472,7 +471,7 @@ and [<Class>] public FSharpAccessibilityRights =
and [<Class>] public FSharpGenericParameter =
inherit FSharpSymbol
internal new : Impl.cenv * Typar -> FSharpGenericParameter
internal new : SymbolEnv * Typar -> FSharpGenericParameter
/// Get the name of the generic parameter
member Name: string
......@@ -642,8 +641,8 @@ and [<RequireQualifiedAccess>] public FSharpInlineAnnotation =
and [<Class>] public FSharpMemberOrFunctionOrValue =
inherit FSharpSymbol
internal new : Impl.cenv * ValRef -> FSharpMemberOrFunctionOrValue
internal new : Impl.cenv * Infos.MethInfo -> FSharpMemberOrFunctionOrValue
internal new : SymbolEnv * ValRef -> FSharpMemberOrFunctionOrValue
internal new : SymbolEnv * Infos.MethInfo -> FSharpMemberOrFunctionOrValue
/// Indicates if the member, function or value is in an unresolved assembly
member IsUnresolved : bool
......@@ -896,8 +895,8 @@ and [<Class>] public FSharpActivePatternGroup =
and [<Class>] public FSharpType =
/// Internal use only. Create a ground type.
internal new : g:TcGlobals * thisCcu: CcuThunk * tcImports: TcImports * typ:TType -> FSharpType
internal new : Impl.cenv * typ:TType -> FSharpType
internal new : g:TcGlobals * thisCcu: CcuThunk * thisCcuTyp: ModuleOrNamespaceType * tcImports: TcImports * typ:TType -> FSharpType
internal new : SymbolEnv * typ:TType -> FSharpType
/// Indicates this is a named type in an unresolved assembly
member IsUnresolved : bool
......@@ -996,21 +995,25 @@ and [<Class>] public FSharpAttribute =
member Format : context: FSharpDisplayContext -> string
/// Represents open declaration in F# code.
[<Sealed>]
type public FSharpOpenDeclaration =
{ /// Idents.
LongId: Ident list
internal new : longId: Ident list * range: range option * modules: FSharpEntity list * appliedScope: range * isOwnNamespace: bool -> FSharpOpenDeclaration
/// Idents.
member LongId: Ident list
/// Range of the open declaration.
Range: range option
/// Range of the open declaration.
member Range: range option
/// Modules or namespaces which is opened with this declaration.
Modules: FSharpEntity list
/// Modules or namespaces which is opened with this declaration.
member Modules: FSharpEntity list
/// Scope in which open declaration is visible.
AppliedScope: range
/// Scope in which open declaration is visible.
member AppliedScope: range
/// If it's `namespace Xxx.Yyy` declaration.
IsOwnNamespace: bool }
/// If it's `namespace Xxx.Yyy` declaration.
member IsOwnNamespace: bool
/// Represents the use of an F# symbol from F# source code
[<Sealed>]
......
此差异已折叠。
......@@ -36,7 +36,7 @@ module Scripting =
#if INTERACTIVE
let argv = Microsoft.FSharp.Compiler.Interactive.Settings.fsi.CommandLineArgs |> Seq.skip 1 |> Seq.toArray
let getCmdLineArgOptional switchName =
let getCmdLineArgOptional (switchName: string) =
argv |> Array.filter(fun t -> t.StartsWith(switchName)) |> Array.map(fun t -> t.Remove(0, switchName.Length).Trim()) |> Array.tryHead
let getCmdLineArg switchName defaultValue =
......
......@@ -2672,6 +2672,30 @@ let ``Test Project16 sym locations`` () =
("val x", ("file1", (11, 11), (11, 12)), ("file1", (11, 11), (11, 12)),("file1", (11, 11), (11, 12)));
("Impl", ("sig1", (2, 7), (2, 11)), ("file1", (2, 7), (2, 11)),("file1", (2, 7), (2, 11)))|]
[<Test>]
let ``Test project16 DeclaringEntity`` () =
let wholeProjectResults =
checker.ParseAndCheckProject(Project16.options)
|> Async.RunSynchronously
let allSymbolsUses = wholeProjectResults.GetAllUsesOfAllSymbols() |> Async.RunSynchronously
for sym in allSymbolsUses do
match sym.Symbol with
| :? FSharpEntity as e when not e.IsNamespace || e.AccessPath.Contains(".") ->
printfn "checking declaring type of entity '%s' --> '%s', assembly = '%s'" e.AccessPath e.CompiledName (e.Assembly.ToString())
shouldEqual e.DeclaringEntity.IsSome (e.AccessPath <> "global")
match e.AccessPath with
| "C" | "D" | "E" | "F" | "G" ->
shouldEqual e.AccessPath "Impl"
shouldEqual e.DeclaringEntity.Value.IsFSharpModule true
shouldEqual e.DeclaringEntity.Value.IsNamespace false
| "int" ->
shouldEqual e.AccessPath "Microsoft.FSharp.Core"
shouldEqual e.DeclaringEntity.Value.AccessPath "Microsoft.FSharp"
| _ -> ()
| :? FSharpMemberOrFunctionOrValue as e when e.IsModuleValueOrMember ->
printfn "checking declaring type of value '%s', assembly = '%s'" e.CompiledName (e.Assembly.ToString())
shouldEqual e.DeclaringEntity.IsSome true
| _ -> ()
//-----------------------------------------------------------------------------------------
......@@ -4636,7 +4660,7 @@ module internal Project37 =
let projFileName = Path.ChangeExtension(base2, ".fsproj")
let fileSource1 = """
namespace AttrTests
type X = int list
[<System.AttributeUsage(System.AttributeTargets.Method ||| System.AttributeTargets.Assembly) >]
type AttrTestAttribute() =
inherit System.Attribute()
......@@ -4665,6 +4689,8 @@ module Test =
let withTypeArray = 0
[<AttrTest([| 0; 1; 2 |])>]
let withIntArray = 0
module NestedModule =
type NestedRecordType = { B : int }
[<assembly: AttrTest()>]
do ()
......@@ -4722,21 +4748,56 @@ let ``Test project37 typeof and arrays in attribute constructor arguments`` () =
a |> shouldEqual [| 0; 1; 2 |]
| _ -> ()
| _ -> ()
wholeProjectResults.AssemblySignature.Attributes
|> Seq.map (fun a -> a.AttributeType.CompiledName)
|> Array.ofSeq |> shouldEqual [| "AttrTestAttribute"; "AttrTest2Attribute" |]
wholeProjectResults.ProjectContext.GetReferencedAssemblies()
|> Seq.find (fun a -> a.SimpleName = "mscorlib")
|> fun a ->
printfn "Attributes found in mscorlib: %A" a.Contents.Attributes
shouldEqual (a.Contents.Attributes.Count > 0) true
wholeProjectResults.ProjectContext.GetReferencedAssemblies()
|> Seq.find (fun a -> a.SimpleName = "FSharp.Core")
|> fun a ->
printfn "Attributes found in FSharp.Core: %A" a.Contents.Attributes
shouldEqual (a.Contents.Attributes.Count > 0) true
let mscorlibAsm =
wholeProjectResults.ProjectContext.GetReferencedAssemblies()
|> Seq.find (fun a -> a.SimpleName = "mscorlib")
printfn "Attributes found in mscorlib: %A" mscorlibAsm.Contents.Attributes
shouldEqual (mscorlibAsm.Contents.Attributes.Count > 0) true
let fsharpCoreAsm =
wholeProjectResults.ProjectContext.GetReferencedAssemblies()
|> Seq.find (fun a -> a.SimpleName = "FSharp.Core")
printfn "Attributes found in FSharp.Core: %A" fsharpCoreAsm.Contents.Attributes
shouldEqual (fsharpCoreAsm.Contents.Attributes.Count > 0) true
[<Test>]
let ``Test project37 DeclaringEntity`` () =
let wholeProjectResults =
checker.ParseAndCheckProject(Project37.options)
|> Async.RunSynchronously
let allSymbolsUses = wholeProjectResults.GetAllUsesOfAllSymbols() |> Async.RunSynchronously
for sym in allSymbolsUses do
match sym.Symbol with
| :? FSharpEntity as e when not e.IsNamespace || e.AccessPath.Contains(".") ->
printfn "checking declaring type of entity '%s' --> '%s', assembly = '%s'" e.AccessPath e.CompiledName (e.Assembly.ToString())
shouldEqual e.DeclaringEntity.IsSome true
match e.CompiledName with
| "AttrTestAttribute" ->
shouldEqual e.AccessPath "AttrTests"
| "int" ->
shouldEqual e.AccessPath "Microsoft.FSharp.Core"
shouldEqual e.DeclaringEntity.Value.AccessPath "Microsoft.FSharp"
| "list`1" ->
shouldEqual e.AccessPath "Microsoft.FSharp.Collections"
shouldEqual e.DeclaringEntity.Value.AccessPath "Microsoft.FSharp"
shouldEqual e.DeclaringEntity.Value.DeclaringEntity.IsSome true
shouldEqual e.DeclaringEntity.Value.DeclaringEntity.Value.IsNamespace true
shouldEqual e.DeclaringEntity.Value.DeclaringEntity.Value.AccessPath "Microsoft"
shouldEqual e.DeclaringEntity.Value.DeclaringEntity.Value.DeclaringEntity.Value.DeclaringEntity.IsSome false
| "Attribute" ->
shouldEqual e.AccessPath "System"
shouldEqual e.DeclaringEntity.Value.AccessPath "global"
| "NestedRecordType" ->
shouldEqual e.AccessPath "AttrTests.Test.NestedModule"
shouldEqual e.DeclaringEntity.Value.AccessPath "AttrTests.Test"
shouldEqual e.DeclaringEntity.Value.DeclaringEntity.Value.AccessPath "AttrTests"
shouldEqual e.DeclaringEntity.Value.DeclaringEntity.Value.DeclaringEntity.Value.AccessPath "global"
| _ -> ()
| :? FSharpMemberOrFunctionOrValue as e when e.IsModuleValueOrMember ->
printfn "checking declaring type of value '%s', assembly = '%s'" e.CompiledName (e.Assembly.ToString())
shouldEqual e.DeclaringEntity.IsSome true
| _ -> ()
//-----------------------------------------------------------
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册