csharpfftfsharpintegrationinterpolationlinear-algebramathdifferentiationmatrixnumericsrandomregressionstatisticsmathnet
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3989 lines
207 KiB
3989 lines
207 KiB
// (c) Microsoft Corporation. All rights reserved
|
|
#light
|
|
|
|
/// Loading initial context, reporting errors etc.
|
|
module (* internal *) Microsoft.FSharp.Compiler.Build
|
|
open System
|
|
open System.IO
|
|
open Internal.Utilities
|
|
open Internal.Utilities.Text
|
|
open Microsoft.FSharp.Text
|
|
open Microsoft.FSharp.Compiler.AbstractIL
|
|
open Microsoft.FSharp.Compiler.AbstractIL.IL
|
|
open Microsoft.FSharp.Compiler.AbstractIL.Internal
|
|
open Microsoft.FSharp.Compiler.AbstractIL.Internal.Library
|
|
open Microsoft.FSharp.Compiler.AbstractIL.Extensions.ILX
|
|
open Microsoft.FSharp.Compiler.AbstractIL.Diagnostics
|
|
open Microsoft.FSharp.Compiler.Pickle
|
|
open Microsoft.FSharp.Compiler.Range
|
|
|
|
open Microsoft.FSharp.Compiler
|
|
open Microsoft.FSharp.Compiler.TypeChecker
|
|
|
|
open Microsoft.FSharp.Compiler.SR
|
|
open Microsoft.FSharp.Compiler.DiagnosticMessage
|
|
|
|
module Ilsupp = Microsoft.FSharp.Compiler.AbstractIL.Internal.Support
|
|
module Ilread = Microsoft.FSharp.Compiler.AbstractIL.BinaryReader
|
|
|
|
module Tc = Microsoft.FSharp.Compiler.TypeChecker
|
|
module SR = Microsoft.FSharp.Compiler.SR
|
|
module DM = Microsoft.FSharp.Compiler.DiagnosticMessage
|
|
|
|
open Microsoft.FSharp.Compiler.AbstractIL.IL
|
|
open Microsoft.FSharp.Compiler.Range
|
|
open Microsoft.FSharp.Compiler.Ast
|
|
open Microsoft.FSharp.Compiler.ErrorLogger
|
|
open Microsoft.FSharp.Compiler.Tast
|
|
open Microsoft.FSharp.Compiler.Tastops
|
|
open Microsoft.FSharp.Compiler.Env
|
|
open Microsoft.FSharp.Compiler.Lexhelp
|
|
open Microsoft.FSharp.Compiler.Lib
|
|
open Microsoft.FSharp.Compiler.Infos
|
|
open Microsoft.FSharp.Compiler.ConstraintSolver
|
|
open Microsoft.FSharp.Compiler.MSBuildResolver
|
|
open Microsoft.FSharp.Compiler.Typrelns
|
|
open Internal.Utilities.Debug
|
|
open Microsoft.FSharp.Compiler.Nameres
|
|
open Microsoft.FSharp.Compiler.PrettyNaming
|
|
|
|
#if DEBUG
|
|
let showAssertForUnexpectedException = ref true
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Some Globals
|
|
//--------------------------------------------------------------------------
|
|
|
|
let sigSuffixes = [".mli";".fsi"]
|
|
let implSuffixes = [".ml";".fs";".fsscript";".fsx"]
|
|
let resSuffixes = [".resx"]
|
|
let scriptSuffixes = [".fsscript";".fsx"]
|
|
let lightSyntaxDefaultExtensions : string list = [ ".fs";".fsscript";".fsx";".fsi" ]
|
|
let syntaxFlagRequiredExtensions : string list = [] // lightSyntaxDefaultExtensions
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// ERROR REPORTING
|
|
//--------------------------------------------------------------------------
|
|
|
|
exception HashIncludeNotAllowedInNonScript of range
|
|
exception HashReferenceNotAllowedInNonScript of range
|
|
exception HashReferenceCopyAfterCompileNotAllowedInNonScript of range
|
|
exception HashDirectiveNotAllowedInNonScript of range
|
|
exception FileNameNotResolved of (*filename*) string * (*description of searched locations*) string * range
|
|
exception AssemblyNotResolved of (*originalName*) string * range
|
|
exception LoadedSourceNotFoundIgnoring of (*filename*) string * range
|
|
exception MSBuildReferenceResolutionWarning of (*MSBuild warning code*)string * (*Message*)string * range
|
|
exception MSBuildReferenceResolutionError of (*MSBuild warning code*)string * (*Message*)string * range
|
|
exception DeprecatedCommandLineOption of string * string * range
|
|
exception HashLoadedSourceHasIssues of (*warnings*) exn list * (*errors*) exn list * range
|
|
exception HashLoadedScriptConsideredSource of range
|
|
exception InvalidInternalsVisibleToAssemblyName of (*badName*)string * (*fileName option*) string option
|
|
|
|
|
|
let rec RangeOfError err =
|
|
match err with
|
|
| ErrorFromAddingConstraint(_,err2,_) -> RangeOfError err2
|
|
| ReservedKeyword(_,m)
|
|
| IndentationProblem(_,m)
|
|
| ErrorFromAddingTypeEquation(_,_,_,_,_,m)
|
|
| ErrorFromApplyingDefault(_,_,_,_,_,m)
|
|
| ErrorsFromAddingSubsumptionConstraint(_,_,_,_,_,m)
|
|
| FunctionExpected(_,_,m)
|
|
| BakedInMemberConstraintName(_,m)
|
|
| IndexOutOfRangeExceptionWarning(m)
|
|
| StandardOperatorRedefinitionWarning(_,m)
|
|
| BadEventTransformation(m)
|
|
| ParameterlessStructCtor(m)
|
|
| FieldNotMutable (_,_,m)
|
|
| Recursion (_,_,_,_,m)
|
|
| InvalidRuntimeCoercion(_,_,_,m)
|
|
| IndeterminateRuntimeCoercion(_,_,_,m)
|
|
| IndeterminateStaticCoercion (_,_,_,m)
|
|
| StaticCoercionShouldUseBox (_,_,_,m)
|
|
| CoercionTargetSealed(_,_,m)
|
|
| UpcastUnnecessary(m)
|
|
| Creflect.IgnoringPartOfQuotedTermWarning (_,m)
|
|
|
|
| TypeTestUnnecessary(m)
|
|
| RuntimeCoercionSourceSealed(_,_,m)
|
|
| OverrideDoesntOverride(_,_,_,_,_,m)
|
|
| UnionPatternsBindDifferentNames m
|
|
| UnionCaseWrongArguments (_,_,_,m)
|
|
| TypeIsImplicitlyAbstract m
|
|
| RequiredButNotSpecified (_,_,_,_,m)
|
|
| FunctionValueUnexpected (_,_,m)
|
|
| UnitTypeExpected (_,_,_,m )
|
|
| UseOfAddressOfOperator m
|
|
| DeprecatedThreadStaticBindingWarning(m)
|
|
| NonUniqueInferredAbstractSlot (_,_,_,_,_,m)
|
|
| DefensiveCopyWarning (_,m)
|
|
| DeprecatedClassFieldInference(m)
|
|
| LetRecCheckedAtRuntime m
|
|
| UpperCaseIdentifierInPattern m
|
|
| NotUpperCaseConstructor m
|
|
| RecursiveUseCheckedAtRuntime (_,_,m)
|
|
| LetRecEvaluatedOutOfOrder (_,_,_,m)
|
|
| Error (_,m)
|
|
| SyntaxError (_,m)
|
|
| InternalError (_,m)
|
|
| FullAbstraction(_,m)
|
|
| InterfaceNotRevealed(_,_,m)
|
|
| WrappedError (_,m)
|
|
| Patcompile.MatchIncomplete (_,_,m)
|
|
| Patcompile.RuleNeverMatched m
|
|
| ValNotMutable(_,_,m)
|
|
| ValNotLocal(_,_,m)
|
|
| MissingFields(_,m)
|
|
| OverrideInIntrinsicAugmentation(m)
|
|
| IntfImplInIntrinsicAugmentation(m)
|
|
| OverrideInExtrinsicAugmentation(m)
|
|
| IntfImplInExtrinsicAugmentation(m)
|
|
| ValueRestriction(_,_,_,_,m)
|
|
| LetRecUnsound (_,_,m)
|
|
| Obsolete (_,m)
|
|
| Experimental (_,m)
|
|
| PossibleUnverifiableCode m
|
|
| OCamlCompatibility (_,m)
|
|
| Deprecated(_,m)
|
|
| LibraryUseOnly(m)
|
|
| FieldsFromDifferentTypes (_,_,_,m)
|
|
| IndeterminateType(m)
|
|
| TyconBadArgs(_,_,_,m) -> Some m
|
|
| FieldNotContained(_,arf,frf,_) -> Some arf.Range
|
|
| ValueNotContained(_,_,aval,_,_) -> Some aval.Range
|
|
| ConstrNotContained(_,aval,_,_) -> Some aval.ucase_id.idRange
|
|
| ExnconstrNotContained(_,aexnc,_,_) -> Some aexnc.Range
|
|
| VarBoundTwice(id)
|
|
| UndefinedName(_,_,id,_) -> Some id.idRange
|
|
| Duplicate(_,_,m)
|
|
| NameClash(_,_,_,m,_,_,_)
|
|
| UnresolvedOverloading(_,_,_,_,_,m)
|
|
| PossibleOverload(_,_,m)
|
|
//| PossibleBestOverload(_,_,m)
|
|
| VirtualAugmentationOnNullValuedType(m)
|
|
| NonVirtualAugmentationOnNullValuedType(m)
|
|
| NonRigidTypar(_,_,_,_,_,m)
|
|
| ConstraintSolverTupleDiffLengths(_,_,_,m,_)
|
|
| ConstraintSolverInfiniteTypes(_,_,_,m,_)
|
|
| ConstraintSolverMissingConstraint(_,_,_,m,_)
|
|
| ConstraintSolverTypesNotInEqualityRelation(_,_,_,m,_)
|
|
| ConstraintSolverError(_,m,_)
|
|
| ConstraintSolverTypesNotInSubsumptionRelation(_,_,_,m,_)
|
|
| ConstraintSolverRelatedInformation(_,m,_)
|
|
| SelfRefObjCtor(_,m) -> Some m
|
|
| NotAFunction(_,_,mfun,marg) -> Some mfun
|
|
| UnresolvedReferenceError(_,m) ->Some m
|
|
| UnresolvedPathReference(_,_,m) ->Some m
|
|
| DeprecatedCommandLineOption(_,_,m) ->Some m
|
|
| HashIncludeNotAllowedInNonScript(m)
|
|
| HashReferenceNotAllowedInNonScript(m)
|
|
| HashDirectiveNotAllowedInNonScript(m)
|
|
| HashReferenceCopyAfterCompileNotAllowedInNonScript(m) -> Some m
|
|
| FileNameNotResolved(_,_,m) -> Some m
|
|
| LoadedSourceNotFoundIgnoring(_,m) -> Some m
|
|
| MSBuildReferenceResolutionWarning(_,_,m) -> Some m
|
|
| MSBuildReferenceResolutionError(_,_,m) -> Some m
|
|
| AssemblyNotResolved(_,m) -> Some m
|
|
| HashLoadedSourceHasIssues(_,_,m) -> Some m
|
|
| HashLoadedScriptConsideredSource(m) -> Some m
|
|
|
|
// Strip TargetInvocationException wrappers
|
|
| :? System.Reflection.TargetInvocationException as e ->
|
|
RangeOfError e.InnerException
|
|
|
|
| _ -> None
|
|
|
|
let rec GetErrorNumber err =
|
|
match err with
|
|
(* DO NOT CHANGE THESE NUMBERS *)
|
|
| ErrorFromAddingTypeEquation _ -> 1
|
|
| FunctionExpected _ -> 2
|
|
| NotAFunction _ -> 3
|
|
| IndexOutOfRangeExceptionWarning _ -> 4
|
|
| FieldNotMutable _ -> 5
|
|
| Recursion _ -> 6
|
|
| InvalidRuntimeCoercion _ -> 7
|
|
| IndeterminateRuntimeCoercion _ -> 8
|
|
| PossibleUnverifiableCode _ -> 9
|
|
| SyntaxError _ -> 10
|
|
| IndeterminateStaticCoercion _ -> 13
|
|
| StaticCoercionShouldUseBox _ -> 14
|
|
| RuntimeCoercionSourceSealed _ -> 16
|
|
| OverrideDoesntOverride _ -> 17
|
|
| UnionPatternsBindDifferentNames _ -> 18
|
|
| UnionCaseWrongArguments _ -> 19
|
|
| UnitTypeExpected _ -> 20
|
|
| RecursiveUseCheckedAtRuntime _ -> 21
|
|
| LetRecEvaluatedOutOfOrder _ -> 22
|
|
| NameClash _ -> 23
|
|
| Patcompile.MatchIncomplete _ -> 25
|
|
| Patcompile.RuleNeverMatched _ -> 26
|
|
| ValNotMutable _ -> 27
|
|
| ValNotLocal _ -> 28
|
|
| MissingFields _ -> 29
|
|
| ValueRestriction _ -> 30
|
|
| LetRecUnsound _ -> 31
|
|
| FieldsFromDifferentTypes _ -> 32
|
|
| TyconBadArgs _ -> 33
|
|
| ValueNotContained _ -> 34
|
|
| Deprecated _ -> 35
|
|
| ConstrNotContained _ -> 36
|
|
| Duplicate _ -> 37
|
|
| VarBoundTwice _ -> 38
|
|
| UndefinedName _ -> 39
|
|
| LetRecCheckedAtRuntime _ -> 40
|
|
| UnresolvedOverloading _ -> 41
|
|
| LibraryUseOnly _ -> 42
|
|
| ErrorFromAddingConstraint _ -> 43
|
|
| Obsolete _ -> 44
|
|
| FullAbstraction _ -> 45
|
|
| ReservedKeyword _ -> 46
|
|
| SelfRefObjCtor _ -> 47
|
|
| VirtualAugmentationOnNullValuedType _ -> 48
|
|
| UpperCaseIdentifierInPattern _ -> 49
|
|
| InterfaceNotRevealed _ -> 50
|
|
| UseOfAddressOfOperator _ -> 51
|
|
| DefensiveCopyWarning _ -> 52
|
|
| NotUpperCaseConstructor _ -> 53
|
|
| TypeIsImplicitlyAbstract _ -> 54
|
|
| DeprecatedClassFieldInference _ -> 55
|
|
| DeprecatedThreadStaticBindingWarning _ -> 56
|
|
| Experimental _ -> 57
|
|
| IndentationProblem _ -> 58
|
|
| CoercionTargetSealed _ -> 59
|
|
| OverrideInIntrinsicAugmentation _ -> 60
|
|
| NonVirtualAugmentationOnNullValuedType _ -> 61
|
|
| OCamlCompatibility _ -> 62
|
|
| ExnconstrNotContained _ -> 63
|
|
| NonRigidTypar _ -> 64
|
|
| UpcastUnnecessary _ -> 66
|
|
| TypeTestUnnecessary _ -> 67
|
|
| Creflect.IgnoringPartOfQuotedTermWarning _ -> 68
|
|
| IntfImplInIntrinsicAugmentation _ -> 69
|
|
| NonUniqueInferredAbstractSlot _ -> 70
|
|
| ErrorFromApplyingDefault _ -> 71
|
|
| IndeterminateType _ -> 72
|
|
| InternalError _ -> 73
|
|
| UnresolvedReferenceNoRange _
|
|
| UnresolvedReferenceError _
|
|
| UnresolvedPathReferenceNoRange _
|
|
| UnresolvedPathReference _ -> 74
|
|
| DeprecatedCommandLineOption _ -> 75
|
|
| HashIncludeNotAllowedInNonScript _
|
|
| HashReferenceNotAllowedInNonScript _
|
|
| HashDirectiveNotAllowedInNonScript _
|
|
| HashReferenceCopyAfterCompileNotAllowedInNonScript _ -> 76
|
|
| BakedInMemberConstraintName _ -> 77
|
|
| FileNameNotResolved _ -> 78
|
|
| LoadedSourceNotFoundIgnoring _ -> 79
|
|
| ParameterlessStructCtor _ -> 81
|
|
| MSBuildReferenceResolutionWarning _ -> 82
|
|
| MSBuildReferenceResolutionError _ -> 83
|
|
| AssemblyNotResolved _ -> 84
|
|
| HashLoadedSourceHasIssues _ -> 85
|
|
| StandardOperatorRedefinitionWarning _ -> 86
|
|
| InvalidInternalsVisibleToAssemblyName _ -> 87
|
|
| OverrideInExtrinsicAugmentation _ -> 89
|
|
| IntfImplInExtrinsicAugmentation _ -> 90
|
|
| BadEventTransformation _ -> 91
|
|
| HashLoadedScriptConsideredSource _ -> 92
|
|
|
|
(* DO NOT CHANGE THE NUMBERS *)
|
|
|
|
// Strip TargetInvocationException wrappers
|
|
| :? System.Reflection.TargetInvocationException as e ->
|
|
GetErrorNumber e.InnerException
|
|
|
|
| WrappedError(e,_) -> GetErrorNumber e
|
|
|
|
(* These do not have good error numbers yet *)
|
|
| Error _ -> 191
|
|
| Failure _ -> 192
|
|
| _ -> 193
|
|
|
|
let warningOn err level =
|
|
match err with
|
|
// Level 4 warnings
|
|
| RecursiveUseCheckedAtRuntime _
|
|
| LetRecEvaluatedOutOfOrder _
|
|
| DefensiveCopyWarning _
|
|
| FullAbstraction _ -> level > 3
|
|
// Level 1 - 3 warnings
|
|
| _ -> level > 0
|
|
|
|
let rec SplitRelatedErrors err =
|
|
match err with
|
|
| UnresolvedOverloading(a,overloads,bestOverloads,errors,b,c) ->
|
|
UnresolvedOverloading(a,[],[],[],b,c), (overloads@bestOverloads@errors)
|
|
| ConstraintSolverRelatedInformation(fopt,m2,e) ->
|
|
let e,related = SplitRelatedErrors e
|
|
ConstraintSolverRelatedInformation(fopt,m2,e), related
|
|
| ErrorFromAddingTypeEquation(g,denv,t1,t2,e,m) ->
|
|
let e,related = SplitRelatedErrors e
|
|
ErrorFromAddingTypeEquation(g,denv,t1,t2,e,m) , related
|
|
| ErrorFromApplyingDefault(g,denv,tp,defaultType,e,m) ->
|
|
let e,related = SplitRelatedErrors e
|
|
ErrorFromApplyingDefault(g,denv,tp,defaultType,e,m) , related
|
|
| ErrorsFromAddingSubsumptionConstraint(g,denv,t1,t2,e,m) ->
|
|
let e,related = SplitRelatedErrors e
|
|
ErrorsFromAddingSubsumptionConstraint(g,denv,t1,t2,e,m), related
|
|
| ErrorFromAddingConstraint(x,e,m) ->
|
|
let e,related = SplitRelatedErrors e
|
|
ErrorFromAddingConstraint(x,e,m), related
|
|
| WrappedError (e,m) ->
|
|
let e,related = SplitRelatedErrors e
|
|
WrappedError(e,m), related
|
|
// Strip TargetInvocationException wrappers
|
|
| :? System.Reflection.TargetInvocationException as e ->
|
|
SplitRelatedErrors e.InnerException
|
|
| _ ->
|
|
err, []
|
|
|
|
|
|
|
|
let stringsOfTypes denv ts =
|
|
let _,ts,tpcs = PrettyTypes.PrettifyTypesN denv.g ts
|
|
let denvMin = { denv with showImperativeTyparAnnotations=false; showConstraintTyparAnnotations=false }
|
|
List.map (NicePrint.string_of_typ denvMin) ts
|
|
|
|
// If the output text is different without showing constraints and/or imperative type variable
|
|
// annotations and/or fully qualifying paths then don't show them!
|
|
let minimalStringsOfTwoTypes denv t1 t2=
|
|
let _,(t1,t2),tpcs = PrettyTypes.PrettifyTypes2 denv.g (t1,t2)
|
|
// try denv + no type annotations
|
|
let denvMin = { denv with showImperativeTyparAnnotations=false; showConstraintTyparAnnotations=false }
|
|
let min1 = NicePrint.string_of_typ denvMin t1
|
|
let min2 = NicePrint.string_of_typ denvMin t2
|
|
if min1 <> min2 then (min1,min2,"") else
|
|
// try denv + no type annotations + show full paths
|
|
let denvMinWithAllPaths = { denvMin with openTopPaths=[] }.Normalize()
|
|
let min1 = NicePrint.string_of_typ denvMinWithAllPaths t1
|
|
let min2 = NicePrint.string_of_typ denvMinWithAllPaths t2
|
|
// try denv
|
|
if min1 <> min2 then (min1,min2,"") else
|
|
let min1 = NicePrint.string_of_typ denv t1
|
|
let min2 = NicePrint.string_of_typ denv t2
|
|
if min1 <> min2 then (min1,min2,NicePrint.string_of_typar_constraints denv tpcs) else
|
|
// try denv + show full paths
|
|
let denvWithAllPaths = { denv with openTopPaths=[] }.Normalize()
|
|
let min1 = NicePrint.string_of_typ denv t1
|
|
let min2 = NicePrint.string_of_typ denv t2
|
|
(min1,min2,NicePrint.string_of_typar_constraints denv tpcs)
|
|
|
|
|
|
// Note: Always show imperative annotations when comparing value signatures
|
|
let minimalStringsOfTwoValues denv v1 v2=
|
|
let denvMin = { denv with showImperativeTyparAnnotations=true; showConstraintTyparAnnotations=false }
|
|
let min1 = bufs (fun buf -> NicePrint.output_qualified_val_spec denvMin buf v1)
|
|
let min2 = bufs (fun buf -> NicePrint.output_qualified_val_spec denvMin buf v2)
|
|
if min1 <> min2 then (min1,min2) else
|
|
let denvMax = { denv with showImperativeTyparAnnotations=true; showConstraintTyparAnnotations=true }
|
|
let max1 = bufs (fun buf -> NicePrint.output_qualified_val_spec denvMax buf v1)
|
|
let max2 = bufs (fun buf -> NicePrint.output_qualified_val_spec denvMax buf v2)
|
|
max1,max2
|
|
|
|
let DeclareMesssage = DM.DeclareResourceString
|
|
|
|
let SeeAlsoE = DeclareResourceString("SeeAlso","%s")
|
|
let ConstraintSolverTupleDiffLengthsE = DeclareResourceString("ConstraintSolverTupleDiffLengths","%d%d")
|
|
let ConstraintSolverInfiniteTypesE = DeclareResourceString("ConstraintSolverInfiniteTypes", "%s%s")
|
|
let ConstraintSolverMissingConstraintE = DeclareResourceString("ConstraintSolverMissingConstraint","%s")
|
|
let ConstraintSolverTypesNotInEqualityRelation1E = DeclareResourceString("ConstraintSolverTypesNotInEqualityRelation1","%s%s")
|
|
let ConstraintSolverTypesNotInEqualityRelation2E = DeclareResourceString("ConstraintSolverTypesNotInEqualityRelation2", "%s%s")
|
|
let ConstraintSolverTypesNotInSubsumptionRelationE = DeclareResourceString("ConstraintSolverTypesNotInSubsumptionRelation","%s%s%s")
|
|
let ConstraintSolverErrorE = DeclareResourceString("ConstraintSolverError","%s")
|
|
let ErrorFromAddingTypeEquation1E = DeclareResourceString("ErrorFromAddingTypeEquation1","%s%s%s")
|
|
let ErrorFromAddingTypeEquation2E = DeclareResourceString("ErrorFromAddingTypeEquation2","%s%s%s")
|
|
let ErrorFromApplyingDefault1E = DeclareResourceString("ErrorFromApplyingDefault1","%s")
|
|
let ErrorFromApplyingDefault2E = DeclareResourceString("ErrorFromApplyingDefault2","")
|
|
let ErrorsFromAddingSubsumptionConstraintE = DeclareResourceString("ErrorsFromAddingSubsumptionConstraint","%s%s%s")
|
|
let UpperCaseIdentifierInPatternE = DeclareResourceString("UpperCaseIdentifierInPattern","")
|
|
let NotUpperCaseConstructorE = DeclareResourceString("NotUpperCaseConstructor","")
|
|
let UnresolvedOverloadingE = DeclareResourceString("UnresolvedOverloading","%s")
|
|
let PossibleOverloadE = DeclareResourceString("PossibleOverload","%s")
|
|
let FunctionExpectedE = DeclareResourceString("FunctionExpected","")
|
|
let BakedInMemberConstraintNameE = DeclareResourceString("BakedInMemberConstraintName","%s")
|
|
let IndexOutOfRangeExceptionWarningE = DeclareResourceString("IndexOutOfRangeExceptionWarning","")
|
|
let StandardOperatorRedefinitionWarningE = DeclareResourceString("StandardOperatorRedefinitionWarning","%s")
|
|
let BadEventTransformationE = DeclareResourceString("BadEventTransformation","")
|
|
let ParameterlessStructCtorE = DeclareResourceString("ParameterlessStructCtor","")
|
|
let InterfaceNotRevealedE = DeclareResourceString("InterfaceNotRevealed","%s")
|
|
let NotAFunction1E = DeclareResourceString("NotAFunction1","")
|
|
let NotAFunction2E = DeclareResourceString("NotAFunction2","")
|
|
let TyconBadArgsE = DeclareResourceString("TyconBadArgs","%s%d%d")
|
|
let IndeterminateTypeE = DeclareResourceString("IndeterminateType","")
|
|
let NameClash1E = DeclareResourceString("NameClash1","%s%s")
|
|
let NameClash2E = DeclareResourceString("NameClash2","%s%s%s%s%s")
|
|
let Duplicate1E = DeclareResourceString("Duplicate1","%s")
|
|
let Duplicate2E = DeclareResourceString("Duplicate2","%s%s")
|
|
let UndefinedName1E = DeclareResourceString("UndefinedName1","%s%s")
|
|
let UndefinedName2E = DeclareResourceString("UndefinedName2","")
|
|
let InternalUndefinedTyconItemE = DeclareResourceString("InternalUndefinedTyconItem","%s%s%s")
|
|
let InternalUndefinedItemRefE = DeclareResourceString("InternalUndefinedItemRef","%s%s%s%s")
|
|
let FieldNotMutableE = DeclareResourceString("FieldNotMutable","")
|
|
let FieldsFromDifferentTypesE = DeclareResourceString("FieldsFromDifferentTypes","%s%s")
|
|
let VarBoundTwiceE = DeclareResourceString("VarBoundTwice","%s")
|
|
let RecursionE = DeclareResourceString("Recursion","%s%s%s%s")
|
|
let InvalidRuntimeCoercionE = DeclareResourceString("InvalidRuntimeCoercion","%s%s%s")
|
|
let IndeterminateRuntimeCoercionE = DeclareResourceString("IndeterminateRuntimeCoercion","%s%s")
|
|
let IndeterminateStaticCoercionE = DeclareResourceString("IndeterminateStaticCoercion","%s%s")
|
|
let StaticCoercionShouldUseBoxE = DeclareResourceString("StaticCoercionShouldUseBox","%s%s")
|
|
let TypeIsImplicitlyAbstractE = DeclareResourceString("TypeIsImplicitlyAbstract","")
|
|
let NonRigidTypar1E = DeclareResourceString("NonRigidTypar1","%s%s")
|
|
let NonRigidTypar2E = DeclareResourceString("NonRigidTypar2","%s%s")
|
|
let NonRigidTypar3E = DeclareResourceString("NonRigidTypar3","%s%s")
|
|
let OBlockEndE = DeclareResourceString("Parser.TOKEN.OBLOCKEND","")
|
|
let UnexpectedEndOfInputE = DeclareResourceString("UnexpectedEndOfInput","")
|
|
let UnexpectedE = DeclareResourceString("Unexpected","%s")
|
|
let NONTERM_interactionE = DeclareResourceString("NONTERM.interaction","")
|
|
let NONTERM_hashDirectiveE = DeclareResourceString("NONTERM.hashDirective","")
|
|
let NONTERM_fieldDeclE = DeclareResourceString("NONTERM.fieldDecl","")
|
|
let NONTERM_unionCaseReprE = DeclareResourceString("NONTERM.unionCaseRepr","")
|
|
let NONTERM_localBindingE = DeclareResourceString("NONTERM.localBinding","")
|
|
let NONTERM_hardwhiteLetBindingsE = DeclareResourceString("NONTERM.hardwhiteLetBindings","")
|
|
let NONTERM_classDefnMemberE = DeclareResourceString("NONTERM.classDefnMember","")
|
|
let NONTERM_defnBindingsE = DeclareResourceString("NONTERM.defnBindings","")
|
|
let NONTERM_classMemberSpfnE = DeclareResourceString("NONTERM.classMemberSpfn","")
|
|
let NONTERM_valSpfnE = DeclareResourceString("NONTERM.valSpfn","")
|
|
let NONTERM_tyconSpfnE = DeclareResourceString("NONTERM.tyconSpfn","")
|
|
let NONTERM_anonLambdaExprE = DeclareResourceString("NONTERM.anonLambdaExpr","")
|
|
let NONTERM_attrUnionCaseDeclE = DeclareResourceString("NONTERM.attrUnionCaseDecl","")
|
|
let NONTERM_cPrototypeE = DeclareResourceString("NONTERM.cPrototype","")
|
|
let NONTERM_objectImplementationMembersE = DeclareResourceString("NONTERM.objectImplementationMembers","")
|
|
let NONTERM_ifExprCasesE = DeclareResourceString("NONTERM.ifExprCases","")
|
|
let NONTERM_openDeclE = DeclareResourceString("NONTERM.openDecl","")
|
|
let NONTERM_fileModuleSpecE = DeclareResourceString("NONTERM.fileModuleSpec","")
|
|
let NONTERM_patternClausesE = DeclareResourceString("NONTERM.patternClauses","")
|
|
let NONTERM_beginEndExprE = DeclareResourceString("NONTERM.beginEndExpr","")
|
|
let NONTERM_recdExprE = DeclareResourceString("NONTERM.recdExpr","")
|
|
let NONTERM_tyconDefnE = DeclareResourceString("NONTERM.tyconDefn","")
|
|
let NONTERM_exconCoreE = DeclareResourceString("NONTERM.exconCore","")
|
|
let NONTERM_typeNameInfoE = DeclareResourceString("NONTERM.typeNameInfo","")
|
|
let NONTERM_attributeListE = DeclareResourceString("NONTERM.attributeList","")
|
|
let NONTERM_quoteExprE = DeclareResourceString("NONTERM.quoteExpr","")
|
|
let NONTERM_typeConstraintE = DeclareResourceString("NONTERM.typeConstraint","")
|
|
let NONTERM_Category_ImplementationFileE = DeclareResourceString("NONTERM.Category.ImplementationFile","")
|
|
let NONTERM_Category_DefinitionE = DeclareResourceString("NONTERM.Category.Definition","")
|
|
let NONTERM_Category_SignatureFileE = DeclareResourceString("NONTERM.Category.SignatureFile","")
|
|
let NONTERM_Category_PatternE = DeclareResourceString("NONTERM.Category.Pattern","")
|
|
let NONTERM_Category_ExprE = DeclareResourceString("NONTERM.Category.Expr","")
|
|
let NONTERM_Category_TypeE = DeclareResourceString("NONTERM.Category.Type","")
|
|
let NONTERM_typeArgsActualE = DeclareResourceString("NONTERM.typeArgsActual","")
|
|
let TokenName1E = DeclareResourceString("TokenName1","%s")
|
|
let TokenName1TokenName2E = DeclareResourceString("TokenName1TokenName2","%s%s")
|
|
let TokenName1TokenName2TokenName3E = DeclareResourceString("TokenName1TokenName2TokenName3","%s%s%s")
|
|
let RuntimeCoercionSourceSealed1E = DeclareResourceString("RuntimeCoercionSourceSealed1","%s")
|
|
let RuntimeCoercionSourceSealed2E = DeclareResourceString("RuntimeCoercionSourceSealed2","%s")
|
|
let CoercionTargetSealedE = DeclareResourceString("CoercionTargetSealed","%s")
|
|
let UpcastUnnecessaryE = DeclareResourceString("UpcastUnnecessary","")
|
|
let TypeTestUnnecessaryE = DeclareResourceString("TypeTestUnnecessary","")
|
|
let IgnoringPartOfQuotedTermWarningE = DeclareResourceString("IgnoringPartOfQuotedTermWarning","%s")
|
|
let OverrideDoesntOverride1E = DeclareResourceString("OverrideDoesntOverride1","%s")
|
|
let OverrideDoesntOverride2E = DeclareResourceString("OverrideDoesntOverride2","%s")
|
|
let OverrideDoesntOverride3E = DeclareResourceString("OverrideDoesntOverride3","%s")
|
|
let UnionCaseWrongArgumentsE = DeclareResourceString("UnionCaseWrongArguments","%d%d")
|
|
let UnionPatternsBindDifferentNamesE = DeclareResourceString("UnionPatternsBindDifferentNames","")
|
|
let ValueNotContainedE = DeclareResourceString("ValueNotContained","%s%s%s%s")
|
|
let ConstrNotContainedE = DeclareResourceString("ConstrNotContained","%s%s%s")
|
|
let ExnconstrNotContainedE = DeclareResourceString("ExnconstrNotContained","%s%s%s")
|
|
let FieldNotContainedE = DeclareResourceString("FieldNotContained","%s%s%s")
|
|
let RequiredButNotSpecifiedE = DeclareResourceString("RequiredButNotSpecified","%s%s%s")
|
|
let UseOfAddressOfOperatorE = DeclareResourceString("UseOfAddressOfOperator","")
|
|
let DefensiveCopyWarningE = DeclareResourceString("DefensiveCopyWarning","%s")
|
|
let DeprecatedThreadStaticBindingWarningE = DeclareResourceString("DeprecatedThreadStaticBindingWarning","")
|
|
let DeprecatedClassFieldInferenceE = DeclareResourceString("DeprecatedClassFieldInference","")
|
|
let FunctionValueUnexpectedE = DeclareResourceString("FunctionValueUnexpected","%s")
|
|
let UnitTypeExpected1E = DeclareResourceString("UnitTypeExpected1","%s")
|
|
let UnitTypeExpected2E = DeclareResourceString("UnitTypeExpected2","")
|
|
let RecursiveUseCheckedAtRuntimeE = DeclareResourceString("RecursiveUseCheckedAtRuntime","")
|
|
let LetRecUnsound1E = DeclareResourceString("LetRecUnsound1","%s")
|
|
let LetRecUnsound2E = DeclareResourceString("LetRecUnsound2","%s%s")
|
|
let LetRecUnsoundInnerE = DeclareResourceString("LetRecUnsoundInner","%s")
|
|
let LetRecEvaluatedOutOfOrderE = DeclareResourceString("LetRecEvaluatedOutOfOrder","")
|
|
let LetRecCheckedAtRuntimeE = DeclareResourceString("LetRecCheckedAtRuntime","")
|
|
let SelfRefObjCtor1E = DeclareResourceString("SelfRefObjCtor1","")
|
|
let SelfRefObjCtor2E = DeclareResourceString("SelfRefObjCtor2","")
|
|
let VirtualAugmentationOnNullValuedTypeE = DeclareResourceString("VirtualAugmentationOnNullValuedType","")
|
|
let NonVirtualAugmentationOnNullValuedTypeE = DeclareResourceString("NonVirtualAugmentationOnNullValuedType","")
|
|
let NonUniqueInferredAbstractSlot1E = DeclareResourceString("NonUniqueInferredAbstractSlot1","%s")
|
|
let NonUniqueInferredAbstractSlot2E = DeclareResourceString("NonUniqueInferredAbstractSlot2","")
|
|
let NonUniqueInferredAbstractSlot3E = DeclareResourceString("NonUniqueInferredAbstractSlot3","%s%s")
|
|
let NonUniqueInferredAbstractSlot4E = DeclareResourceString("NonUniqueInferredAbstractSlot4","")
|
|
let ErrorE = DeclareResourceString("Error","%s")
|
|
let Failure3E = DeclareResourceString("Failure3","%s")
|
|
let Failure4E = DeclareResourceString("Failure4","%s")
|
|
let FullAbstractionE = DeclareResourceString("FullAbstraction","%s")
|
|
let MatchIncomplete1E = DeclareResourceString("MatchIncomplete1","")
|
|
let MatchIncomplete2E = DeclareResourceString("MatchIncomplete2","%s")
|
|
let MatchIncomplete3E = DeclareResourceString("MatchIncomplete3","%s")
|
|
let MatchIncomplete4E = DeclareResourceString("MatchIncomplete4","")
|
|
let RuleNeverMatchedE = DeclareResourceString("RuleNeverMatched","")
|
|
let ValNotMutableE = DeclareResourceString("ValNotMutable","")
|
|
let ValNotLocalE = DeclareResourceString("ValNotLocal","")
|
|
let Obsolete1E = DeclareResourceString("Obsolete1","")
|
|
let Obsolete2E = DeclareResourceString("Obsolete2","%s")
|
|
let ExperimentalE = DeclareResourceString("Experimental","%s")
|
|
let PossibleUnverifiableCodeE = DeclareResourceString("PossibleUnverifiableCode","")
|
|
let OCamlCompatibilityE = DeclareResourceString("OCamlCompatibility","%s")
|
|
let DeprecatedE = DeclareResourceString("Deprecated","%s")
|
|
let LibraryUseOnlyE = DeclareResourceString("LibraryUseOnly","")
|
|
let MissingFieldsE = DeclareResourceString("MissingFields","%s")
|
|
let ValueRestriction1E = DeclareResourceString("ValueRestriction1","%s%s%s")
|
|
let ValueRestriction2E = DeclareResourceString("ValueRestriction2","%s%s%s")
|
|
let ValueRestriction3E = DeclareResourceString("ValueRestriction3","%s")
|
|
let ValueRestriction4E = DeclareResourceString("ValueRestriction4","%s%s%s")
|
|
let ValueRestriction5E = DeclareResourceString("ValueRestriction5","%s%s%s")
|
|
let RecoverableParseErrorE = DeclareResourceString("RecoverableParseError","")
|
|
let ReservedKeywordE = DeclareResourceString("ReservedKeyword","%s")
|
|
let IndentationProblemE = DeclareResourceString("IndentationProblem","%s")
|
|
let OverrideInIntrinsicAugmentationE = DeclareResourceString("OverrideInIntrinsicAugmentation","")
|
|
let OverrideInExtrinsicAugmentationE = DeclareResourceString("OverrideInExtrinsicAugmentation","")
|
|
let IntfImplInIntrinsicAugmentationE = DeclareResourceString("IntfImplInIntrinsicAugmentation","")
|
|
let IntfImplInExtrinsicAugmentationE = DeclareResourceString("IntfImplInExtrinsicAugmentation","")
|
|
let UnresolvedReferenceNoRangeE = DeclareResourceString("UnresolvedReferenceNoRange","%s")
|
|
let UnresolvedPathReferenceNoRangeE = DeclareResourceString("UnresolvedPathReferenceNoRange","%s%s")
|
|
let DeprecatedCommandLineOptionE = DeclareResourceString("DeprecatedCommandLineOption","%s%s")
|
|
let HashIncludeNotAllowedInNonScriptE = DeclareResourceString("HashIncludeNotAllowedInNonScript","")
|
|
let HashReferenceNotAllowedInNonScriptE = DeclareResourceString("HashReferenceNotAllowedInNonScript","")
|
|
let HashReferenceCopyAfterCompileNotAllowedInNonScriptE = DeclareResourceString("HashReferenceCopyAfterCompileNotAllowedInNonScript","")
|
|
let HashDirectiveNotAllowedInNonScriptE = DeclareResourceString("HashDirectiveNotAllowedInNonScript","")
|
|
let FileNameNotResolvedE = DeclareResourceString("FileNameNotResolved","%s%s")
|
|
let AssemblyNotResolvedE = DeclareResourceString("AssemblyNotResolved","%s")
|
|
let HashLoadedSourceHasIssues1E = DeclareResourceString("HashLoadedSourceHasIssues1","")
|
|
let HashLoadedSourceHasIssues2E = DeclareResourceString("HashLoadedSourceHasIssues2","")
|
|
let HashLoadedScriptConsideredSourceE = DeclareResourceString("HashLoadedScriptConsideredSource","")
|
|
let InvalidInternalsVisibleToAssemblyName1E = DeclareResourceString("InvalidInternalsVisibleToAssemblyName1","%s%s")
|
|
let InvalidInternalsVisibleToAssemblyName2E = DeclareResourceString("InvalidInternalsVisibleToAssemblyName2","%s")
|
|
let LoadedSourceNotFoundIgnoringE = DeclareResourceString("LoadedSourceNotFoundIgnoring","%s")
|
|
let MSBuildReferenceResolutionErrorE = DeclareResourceString("MSBuildReferenceResolutionError","%s%s")
|
|
let TargetInvocationExceptionWrapperE = DeclareResourceString("TargetInvocationExceptionWrapper","%s")
|
|
|
|
let getErrorString = SR.GetString
|
|
|
|
let rec OutputExceptionR (os:System.Text.StringBuilder) exn =
|
|
match exn with
|
|
| ConstraintSolverTupleDiffLengths(denv,tl1,tl2,m,m2) ->
|
|
os.Append(ConstraintSolverTupleDiffLengthsE.Format (List.length tl1) (List.length tl2)) |> ignore;
|
|
(if start_line_of_range m <> start_line_of_range m2 then
|
|
os.Append(SeeAlsoE.Format (string_of_range m)) |> ignore);
|
|
| ConstraintSolverInfiniteTypes(denv,t1,t2,m,m2) ->
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv t1 t2
|
|
os.Append(ConstraintSolverInfiniteTypesE.Format t1 t2) |> ignore;
|
|
(if start_line_of_range m <> start_line_of_range m2 then
|
|
os.Append(SeeAlsoE.Format (string_of_range m)) |> ignore );
|
|
| ConstraintSolverMissingConstraint(denv,tpr,tpc,m,m2) ->
|
|
os.Append(ConstraintSolverMissingConstraintE.Format (NicePrint.string_of_typar_constraint denv (tpr,tpc))) |> ignore;
|
|
(if start_line_of_range m <> start_line_of_range m2 then
|
|
os.Append(SeeAlsoE.Format (string_of_range m)) |> ignore );
|
|
| ConstraintSolverTypesNotInEqualityRelation(denv,(TType_measure _ as t1),(TType_measure _ as t2),m,m2) ->
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv t1 t2
|
|
os.Append(ConstraintSolverTypesNotInEqualityRelation1E.Format t1 t2) |> ignore;
|
|
(if start_line_of_range m <> start_line_of_range m2 then
|
|
os.Append(SeeAlsoE.Format (string_of_range m)) |> ignore);
|
|
| ConstraintSolverTypesNotInEqualityRelation(denv,t1,t2,m,m2) ->
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv t1 t2
|
|
os.Append(ConstraintSolverTypesNotInEqualityRelation2E.Format t1 t2) |> ignore;
|
|
(if start_line_of_range m <> start_line_of_range m2 then
|
|
os.Append(SeeAlsoE.Format (string_of_range m)) |> ignore);
|
|
| ConstraintSolverTypesNotInSubsumptionRelation(denv,t1,t2,m,m2) ->
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv t1 t2
|
|
os.Append(ConstraintSolverTypesNotInSubsumptionRelationE.Format t2 t1 tpcs) |> ignore;
|
|
(if start_line_of_range m <> start_line_of_range m2 then
|
|
os.Append(SeeAlsoE.Format (string_of_range m2)) |> ignore);
|
|
| ConstraintSolverError(msg,m,m2) ->
|
|
os.Append(ConstraintSolverErrorE.Format msg) |> ignore;
|
|
(if start_line_of_range m <> start_line_of_range m2 then
|
|
os.Append(SeeAlsoE.Format (string_of_range m2)) |> ignore);
|
|
| ConstraintSolverRelatedInformation(fopt,m2,e) ->
|
|
match e with
|
|
| ConstraintSolverError _ -> OutputExceptionR os e;
|
|
| _ -> ()
|
|
fopt |> Option.iter (Printf.bprintf os " %s")
|
|
| ErrorFromAddingTypeEquation(g,denv,t1,t2,ConstraintSolverTypesNotInEqualityRelation(_,t1',t2',m,_),_)
|
|
when type_equiv g t1 t1'
|
|
&& type_equiv g t2 t2' ->
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv t1 t2
|
|
os.Append(ErrorFromAddingTypeEquation1E.Format t2 t1 tpcs) |> ignore
|
|
| ErrorFromAddingTypeEquation(g,denv,_,_,((ConstraintSolverTypesNotInSubsumptionRelation _ | ConstraintSolverError _) as e),m) ->
|
|
OutputExceptionR os e;
|
|
| ErrorFromAddingTypeEquation(g,denv,t1,t2,e,m) ->
|
|
if not (type_equiv g t1 t2) then (
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv t1 t2
|
|
if t1<>t2 ^ tpcs then os.Append(ErrorFromAddingTypeEquation2E.Format t1 t2 tpcs) |> ignore;
|
|
);
|
|
OutputExceptionR os e
|
|
| ErrorFromApplyingDefault(g,denv,tp,defaultType,e,m) ->
|
|
let defaultType = List.hd (stringsOfTypes denv [defaultType])
|
|
os.Append(ErrorFromApplyingDefault1E.Format defaultType) |> ignore
|
|
OutputExceptionR os e
|
|
os.Append(ErrorFromApplyingDefault2E.Format) |> ignore
|
|
| ErrorsFromAddingSubsumptionConstraint(g,denv,t1,t2,e,m) ->
|
|
if not (type_equiv g t1 t2) then (
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv t1 t2
|
|
if t1 <> (t2 ^ tpcs) then
|
|
os.Append(ErrorsFromAddingSubsumptionConstraintE.Format t2 t1 tpcs) |> ignore
|
|
);
|
|
OutputExceptionR os e
|
|
| UpperCaseIdentifierInPattern(m) ->
|
|
os.Append(UpperCaseIdentifierInPatternE.Format) |> ignore
|
|
| NotUpperCaseConstructor(m) ->
|
|
os.Append(NotUpperCaseConstructorE.Format) |> ignore
|
|
| ErrorFromAddingConstraint(_,e,_) ->
|
|
OutputExceptionR os e;
|
|
| UnresolvedOverloading(_,_,_,_,mtext,m) ->
|
|
os.Append(UnresolvedOverloadingE.Format mtext) |> ignore
|
|
| PossibleOverload(_,minfo,m) ->
|
|
os.Append(PossibleOverloadE.Format minfo) |> ignore
|
|
//| PossibleBestOverload(_,minfo,m) ->
|
|
// Printf.bprintf os "\n\nPossible best overload: '%s'." minfo
|
|
| FunctionExpected(denv,t,m) ->
|
|
os.Append(FunctionExpectedE.Format) |> ignore
|
|
| BakedInMemberConstraintName(nm,m) ->
|
|
os.Append(BakedInMemberConstraintNameE.Format nm) |> ignore
|
|
| IndexOutOfRangeExceptionWarning(m) ->
|
|
os.Append(IndexOutOfRangeExceptionWarningE.Format) |> ignore
|
|
| StandardOperatorRedefinitionWarning(msg,_) ->
|
|
os.Append(StandardOperatorRedefinitionWarningE.Format msg) |> ignore
|
|
| BadEventTransformation(m) ->
|
|
os.Append(BadEventTransformationE.Format) |> ignore
|
|
| ParameterlessStructCtor(m) ->
|
|
os.Append(ParameterlessStructCtorE.Format) |> ignore
|
|
| InterfaceNotRevealed(denv,ity,m) ->
|
|
os.Append(InterfaceNotRevealedE.Format (NicePrint.pretty_string_of_typ denv ity)) |> ignore
|
|
| NotAFunction(denv,t,mfun,marg) ->
|
|
if start_col_of_range marg = 0 then
|
|
os.Append(NotAFunction1E.Format) |> ignore
|
|
else
|
|
os.Append(NotAFunction2E.Format) |> ignore
|
|
|
|
| TyconBadArgs(denv,tcref,d,m) ->
|
|
let exp = tcref.TyparsNoRange.Length
|
|
os.Append(TyconBadArgsE.Format (full_display_text_of_tcref tcref) exp d) |> ignore
|
|
| IndeterminateType(m) ->
|
|
os.Append(IndeterminateTypeE.Format) |> ignore
|
|
| NameClash(nm,k1,nm1,m1,k2,nm2,m2) ->
|
|
if nm = nm1 && nm1 = nm2 && k1 = k2 then
|
|
os.Append(NameClash1E.Format k1 nm1) |> ignore
|
|
else
|
|
os.Append(NameClash2E.Format k1 nm1 nm k2 nm2) |> ignore
|
|
| Duplicate(k,s,m) ->
|
|
if k = "member" then
|
|
os.Append(Duplicate1E.Format (DecompileOpName s)) |> ignore
|
|
else
|
|
os.Append(Duplicate2E.Format k (DecompileOpName s)) |> ignore
|
|
| UndefinedName(_,k,id,avail) ->
|
|
os.Append(UndefinedName1E.Format k (DecompileOpName id.idText)) |> ignore
|
|
if List.mem id.idText
|
|
[ "open_out"; "pred"; "succ"; "min_int"; "max_int"; "End_of_file"; "Out_of_memory";
|
|
"Division_by_zero"; "Stack_overflow"; "Not_found"; "Match_failure"; "Assert_failure";
|
|
"Invalid_argument"; "!="; "=="; "+."; "-."; "*."; "/."; "abs_float"; "max_float"; "min_float";
|
|
"epsilon_float"; "mod_float"; "modf"; "nonempty"; "neg_infinity"; "ldexp"; "FP_normal";
|
|
"classify_float"; "bool_of_string"; "char_of_int"; "int_of_char"; "int_of_string";
|
|
"int_of_float"; "string_of_bool"; "string_of_float"; "string_of_int"; "float_of_int";
|
|
"float_of_string"; "in_channel"; "open_in"; "open_in_bin"; "open_in_gen";
|
|
"close_in"; "in_channel_length"; "input_byte"; "input_char"; "input_line"; "input_value";
|
|
"pos_in"; "really_input"; "seek_in"; "set_binary_mode_in"; "unsafe_really_input"; "out_channel";
|
|
"open_out"; "open_out_bin"; "open_out_gen"; "close_out"; "out_channel_length";
|
|
"output_byte"; "output_string"; "output_value"; "pos_out"; "seek_out"; "set_binary_mode_out";
|
|
"flush"; "prerr_char"; "prerr_endline"; "prerr_float"; "prerr_int"; "prerr_newline";
|
|
"prerr_string"; "print_char"; "print_endline"; "print_float"; "print_int"; "print_newline";
|
|
"mem"; "assoc"; "try_assoc"; "mem_assoc"; "remove_assoc"; "assq";"try_assq"; "mem_assq";
|
|
"remove_assq"; "memq"; "rev_map"; "rev_map2"; "rev_append"; "scan1_left"; "scan1_right";
|
|
"print_string"; "read_float"; "read_int"; "read_line"; "Pervasives"; "Hashtbl"; "Buffer"; "Tagged"; "HashSet";
|
|
"Parsing"; "Lexing"; "Char"; "Int32"; "Int64"; "UInt32"; "UInt64"; "Int16"; "UInt16"; "Byte";
|
|
"SByte"; "Int8"; "UInt8"; "Obj"; "Num"; "Filename"; "ReadonlyArray"; "Roarray"; "LazyList"; "Big_int"; "Sys";
|
|
"Printexc"; "Float"; "Float32"; "Matrix"; "Vector"; "Complex"; "generate_using"; "generate"; "complex"; "RowVector"; "matrix"; "vector"; "rowvec";
|
|
// String.* functions
|
|
"split"; "lowercase"; "contains"; "contains_between"; "contains_from"; "capitalize"; "uncapitalize"; "uppercase"; "trim" ] then
|
|
os.Append(UndefinedName2E.Format) |> ignore
|
|
|
|
| InternalUndefinedTyconItem(k,tcref,s) ->
|
|
os.Append(InternalUndefinedTyconItemE.Format (full_display_text_of_tcref tcref) k s) |> ignore
|
|
| InternalUndefinedItemRef(k,smr,ccuName,s) ->
|
|
os.Append(InternalUndefinedItemRefE.Format smr ccuName k s) |> ignore
|
|
| FieldNotMutable (denv,fref,m) ->
|
|
os.Append(FieldNotMutableE.Format) |> ignore
|
|
| FieldsFromDifferentTypes (denv,fref1,fref2,m) ->
|
|
os.Append(FieldsFromDifferentTypesE.Format fref1.FieldName fref2.FieldName) |> ignore
|
|
| VarBoundTwice(id) ->
|
|
os.Append(VarBoundTwiceE.Format (DecompileOpName id.idText)) |> ignore
|
|
| Recursion (denv,id,ty1,ty2,m) ->
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv ty1 ty2
|
|
os.Append(RecursionE.Format (DecompileOpName id.idText) t1 t2 tpcs) |> ignore
|
|
| InvalidRuntimeCoercion(denv,ty1,ty2,m) ->
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv ty1 ty2
|
|
os.Append(InvalidRuntimeCoercionE.Format t1 t2 tpcs) |> ignore
|
|
| IndeterminateRuntimeCoercion(denv,ty1,ty2,m) ->
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv ty1 ty2
|
|
os.Append(IndeterminateRuntimeCoercionE.Format t1 t2) |> ignore
|
|
| IndeterminateStaticCoercion(denv,ty1,ty2,m) ->
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv ty1 ty2
|
|
os.Append(IndeterminateStaticCoercionE.Format t1 t2) |> ignore
|
|
| StaticCoercionShouldUseBox(denv,ty1,ty2,m) ->
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv ty1 ty2
|
|
os.Append(StaticCoercionShouldUseBoxE.Format t1 t2) |> ignore
|
|
| TypeIsImplicitlyAbstract(m) ->
|
|
os.Append(TypeIsImplicitlyAbstractE.Format) |> ignore
|
|
| NonRigidTypar(denv,tpnmOpt,typarRange,ty1,ty,m) ->
|
|
let _,(ty1,ty),tpcs = PrettyTypes.PrettifyTypes2 denv.g (ty1,ty)
|
|
match tpnmOpt with
|
|
| None ->
|
|
os.Append(NonRigidTypar1E.Format (string_of_range typarRange) (NicePrint.string_of_typ denv ty)) |> ignore
|
|
| Some tpnm ->
|
|
match ty1 with
|
|
| TType_measure _ ->
|
|
os.Append(NonRigidTypar2E.Format tpnm (NicePrint.string_of_typ denv ty)) |> ignore
|
|
| _ ->
|
|
os.Append(NonRigidTypar3E.Format tpnm (NicePrint.string_of_typ denv ty)) |> ignore
|
|
| SyntaxError (ctxt,m) ->
|
|
let ctxt = unbox<Parsing.ParseErrorContext<Parser.token>>(ctxt)
|
|
let tokenIdToText tid =
|
|
match tid with
|
|
| Parser.TOKEN_IDENT -> getErrorString("Parser.TOKEN.IDENT")
|
|
| Parser.TOKEN_BIGNUM
|
|
| Parser.TOKEN_INT8
|
|
| Parser.TOKEN_UINT8
|
|
| Parser.TOKEN_INT16
|
|
| Parser.TOKEN_UINT16
|
|
| Parser.TOKEN_INT32
|
|
| Parser.TOKEN_UINT32
|
|
| Parser.TOKEN_INT64
|
|
| Parser.TOKEN_UINT64
|
|
| Parser.TOKEN_UNATIVEINT
|
|
| Parser.TOKEN_NATIVEINT -> getErrorString("Parser.TOKEN.INT")
|
|
| Parser.TOKEN_IEEE32
|
|
| Parser.TOKEN_IEEE64 -> getErrorString("Parser.TOKEN.FLOAT")
|
|
| Parser.TOKEN_DECIMAL -> getErrorString("Parser.TOKEN.DECIMAL")
|
|
| Parser.TOKEN_CHAR -> getErrorString("Parser.TOKEN.CHAR")
|
|
|
|
| Parser.TOKEN_BASE -> getErrorString("Parser.TOKEN.BASE")
|
|
| Parser.TOKEN_LPAREN_STAR_RPAREN -> getErrorString("Parser.TOKEN.LPAREN.STAR.RPAREN")
|
|
| Parser.TOKEN_DOLLAR -> getErrorString("Parser.TOKEN.DOLLAR")
|
|
| Parser.TOKEN_INFIX_STAR_STAR_OP -> getErrorString("Parser.TOKEN.INFIX.STAR.STAR.OP")
|
|
| Parser.TOKEN_INFIX_COMPARE_OP -> getErrorString("Parser.TOKEN.INFIX.COMPARE.OP")
|
|
| Parser.TOKEN_COLON_GREATER -> getErrorString("Parser.TOKEN.COLON.GREATER")
|
|
| Parser.TOKEN_COLON_COLON ->getErrorString("Parser.TOKEN.COLON.COLON")
|
|
| Parser.TOKEN_PERCENT_OP -> getErrorString("Parser.TOKEN.PERCENT.OP")
|
|
| Parser.TOKEN_INFIX_AT_HAT_OP -> getErrorString("Parser.TOKEN.INFIX.AT.HAT.OP")
|
|
| Parser.TOKEN_INFIX_BAR_OP -> getErrorString("Parser.TOKEN.INFIX.BAR.OP")
|
|
| Parser.TOKEN_PLUS_MINUS_OP -> getErrorString("Parser.TOKEN.PLUS.MINUS.OP")
|
|
| Parser.TOKEN_PREFIX_OP -> getErrorString("Parser.TOKEN.PREFIX.OP")
|
|
| Parser.TOKEN_COLON_QMARK_GREATER -> getErrorString("Parser.TOKEN.COLON.QMARK.GREATER")
|
|
| Parser.TOKEN_INFIX_STAR_DIV_MOD_OP -> getErrorString("Parser.TOKEN.INFIX.STAR.DIV.MOD.OP")
|
|
| Parser.TOKEN_INFIX_AMP_OP -> getErrorString("Parser.TOKEN.INFIX.AMP.OP")
|
|
| Parser.TOKEN_AMP -> getErrorString("Parser.TOKEN.AMP")
|
|
| Parser.TOKEN_AMP_AMP -> getErrorString("Parser.TOKEN.AMP.AMP")
|
|
| Parser.TOKEN_BAR_BAR -> getErrorString("Parser.TOKEN.BAR.BAR")
|
|
| Parser.TOKEN_LESS -> getErrorString("Parser.TOKEN.LESS")
|
|
| Parser.TOKEN_GREATER -> getErrorString("Parser.TOKEN.GREATER")
|
|
| Parser.TOKEN_QMARK -> getErrorString("Parser.TOKEN.QMARK")
|
|
| Parser.TOKEN_QMARK_QMARK -> getErrorString("Parser.TOKEN.QMARK.QMARK")
|
|
| Parser.TOKEN_COLON_QMARK-> getErrorString("Parser.TOKEN.COLON.QMARK")
|
|
| Parser.TOKEN_INT32_DOT_DOT -> getErrorString("Parser.TOKEN.INT32.DOT.DOT")
|
|
| Parser.TOKEN_DOT_DOT -> getErrorString("Parser.TOKEN.DOT.DOT")
|
|
| Parser.TOKEN_QUOTE -> getErrorString("Parser.TOKEN.QUOTE")
|
|
| Parser.TOKEN_STAR -> getErrorString("Parser.TOKEN.STAR")
|
|
| Parser.TOKEN_HIGH_PRECEDENCE_TYAPP -> getErrorString("Parser.TOKEN.HIGH.PRECEDENCE.TYAPP")
|
|
| Parser.TOKEN_COLON -> getErrorString("Parser.TOKEN.COLON")
|
|
| Parser.TOKEN_COLON_EQUALS -> getErrorString("Parser.TOKEN.COLON.EQUALS")
|
|
| Parser.TOKEN_LARROW -> getErrorString("Parser.TOKEN.LARROW")
|
|
| Parser.TOKEN_EQUALS -> getErrorString("Parser.TOKEN.EQUALS")
|
|
| Parser.TOKEN_GREATER_DOT -> getErrorString("Parser.TOKEN.GREATER.DOT")
|
|
| Parser.TOKEN_GREATER_BAR_RBRACK -> getErrorString("Parser.TOKEN.GREATER.BAR.RBRACK")
|
|
| Parser.TOKEN_MINUS -> getErrorString("Parser.TOKEN.MINUS")
|
|
| Parser.TOKEN_ADJACENT_PREFIX_PLUS_MINUS_OP -> getErrorString("Parser.TOKEN.ADJACENT.PREFIX.PLUS.MINUS.OP")
|
|
| Parser.TOKEN_FUNKY_OPERATOR_NAME -> getErrorString("Parser.TOKEN.FUNKY.OPERATOR.NAME")
|
|
| Parser.TOKEN_COMMA-> getErrorString("Parser.TOKEN.COMMA")
|
|
| Parser.TOKEN_DOT -> getErrorString("Parser.TOKEN.DOT")
|
|
| Parser.TOKEN_BAR-> getErrorString("Parser.TOKEN.BAR")
|
|
| Parser.TOKEN_HASH -> getErrorString("Parser.TOKEN.HASH")
|
|
| Parser.TOKEN_UNDERSCORE -> getErrorString("Parser.TOKEN.UNDERSCORE")
|
|
| Parser.TOKEN_SEMICOLON -> getErrorString("Parser.TOKEN.SEMICOLON")
|
|
| Parser.TOKEN_SEMICOLON_SEMICOLON-> getErrorString("Parser.TOKEN.SEMICOLON.SEMICOLON")
|
|
| Parser.TOKEN_LPAREN-> getErrorString("Parser.TOKEN.LPAREN")
|
|
| Parser.TOKEN_RPAREN -> getErrorString("Parser.TOKEN.RPAREN")
|
|
| Parser.TOKEN_SPLICE_SYMBOL -> getErrorString("Parser.TOKEN.SPLICE.SYMBOL")
|
|
| Parser.TOKEN_LQUOTE -> getErrorString("Parser.TOKEN.LQUOTE")
|
|
| Parser.TOKEN_LBRACK -> getErrorString("Parser.TOKEN.LBRACK")
|
|
| Parser.TOKEN_LBRACK_BAR -> getErrorString("Parser.TOKEN.LBRACK.BAR")
|
|
| Parser.TOKEN_LBRACK_LESS -> getErrorString("Parser.TOKEN.LBRACK.LESS")
|
|
| Parser.TOKEN_LBRACE -> getErrorString("Parser.TOKEN.LBRACE")
|
|
| Parser.TOKEN_LBRACE_LESS-> getErrorString("Parser.TOKEN.LBRACE.LESS")
|
|
| Parser.TOKEN_BAR_RBRACK -> getErrorString("Parser.TOKEN.BAR.RBRACK")
|
|
| Parser.TOKEN_GREATER_RBRACE -> getErrorString("Parser.TOKEN.GREATER.RBRACE")
|
|
| Parser.TOKEN_GREATER_RBRACK -> getErrorString("Parser.TOKEN.GREATER.RBRACK")
|
|
| Parser.TOKEN_RQUOTE_DOT _
|
|
| Parser.TOKEN_RQUOTE -> getErrorString("Parser.TOKEN.RQUOTE")
|
|
| Parser.TOKEN_RBRACK -> getErrorString("Parser.TOKEN.RBRACK")
|
|
| Parser.TOKEN_RBRACE -> getErrorString("Parser.TOKEN.RBRACE")
|
|
| Parser.TOKEN_PUBLIC -> getErrorString("Parser.TOKEN.PUBLIC")
|
|
| Parser.TOKEN_PRIVATE -> getErrorString("Parser.TOKEN.PRIVATE")
|
|
| Parser.TOKEN_INTERNAL -> getErrorString("Parser.TOKEN.INTERNAL")
|
|
| Parser.TOKEN_CONSTRAINT -> getErrorString("Parser.TOKEN.CONSTRAINT")
|
|
| Parser.TOKEN_INSTANCE -> getErrorString("Parser.TOKEN.INSTANCE")
|
|
| Parser.TOKEN_DELEGATE -> getErrorString("Parser.TOKEN.DELEGATE")
|
|
| Parser.TOKEN_INHERIT -> getErrorString("Parser.TOKEN.INHERIT")
|
|
| Parser.TOKEN_CONSTRUCTOR-> getErrorString("Parser.TOKEN.CONSTRUCTOR")
|
|
| Parser.TOKEN_DEFAULT -> getErrorString("Parser.TOKEN.DEFAULT")
|
|
| Parser.TOKEN_OVERRIDE-> getErrorString("Parser.TOKEN.OVERRIDE")
|
|
| Parser.TOKEN_ABSTRACT-> getErrorString("Parser.TOKEN.ABSTRACT")
|
|
| Parser.TOKEN_VIRTUAL-> getErrorString("Parser.TOKEN.VIRTUAL")
|
|
| Parser.TOKEN_CLASS-> getErrorString("Parser.TOKEN.CLASS")
|
|
| Parser.TOKEN_MEMBER -> getErrorString("Parser.TOKEN.MEMBER")
|
|
| Parser.TOKEN_STATIC -> getErrorString("Parser.TOKEN.STATIC")
|
|
| Parser.TOKEN_NAMESPACE-> getErrorString("Parser.TOKEN.NAMESPACE")
|
|
| Parser.TOKEN_OBLOCKBEGIN -> getErrorString("Parser.TOKEN.OBLOCKBEGIN")
|
|
| Parser.TOKEN_ODECLEND
|
|
| Parser.TOKEN_OBLOCKSEP
|
|
| Parser.TOKEN_OEND
|
|
| Parser.TOKEN_ORIGHT_BLOCK_END
|
|
| Parser.TOKEN_OBLOCKEND -> getErrorString("Parser.TOKEN.OBLOCKEND")
|
|
| Parser.TOKEN_THEN
|
|
| Parser.TOKEN_OTHEN -> getErrorString("Parser.TOKEN.OTHEN")
|
|
| Parser.TOKEN_ELSE
|
|
| Parser.TOKEN_OELSE -> getErrorString("Parser.TOKEN.OELSE")
|
|
| Parser.TOKEN_LET(_)
|
|
| Parser.TOKEN_OLET(_) -> getErrorString("Parser.TOKEN.OLET")
|
|
| Parser.TOKEN_OBINDER
|
|
| Parser.TOKEN_BINDER -> getErrorString("Parser.TOKEN.BINDER")
|
|
| Parser.TOKEN_ODO -> getErrorString("Parser.TOKEN.ODO")
|
|
| Parser.TOKEN_OWITH -> getErrorString("Parser.TOKEN.OWITH")
|
|
| Parser.TOKEN_OFUNCTION -> getErrorString("Parser.TOKEN.OFUNCTION")
|
|
| Parser.TOKEN_OFUN -> getErrorString("Parser.TOKEN.OFUN")
|
|
| Parser.TOKEN_ORESET -> getErrorString("Parser.TOKEN.ORESET")
|
|
| Parser.TOKEN_ODUMMY -> getErrorString("Parser.TOKEN.ODUMMY")
|
|
| Parser.TOKEN_DO_BANG
|
|
| Parser.TOKEN_ODO_BANG -> getErrorString("Parser.TOKEN.ODO.BANG")
|
|
| Parser.TOKEN_YIELD -> getErrorString("Parser.TOKEN.YIELD")
|
|
| Parser.TOKEN_YIELD_BANG -> getErrorString("Parser.TOKEN.YIELD.BANG")
|
|
| Parser.TOKEN_OINTERFACE_MEMBER-> getErrorString("Parser.TOKEN.OINTERFACE.MEMBER")
|
|
| Parser.TOKEN_ELIF -> getErrorString("Parser.TOKEN.ELIF")
|
|
| Parser.TOKEN_RARROW -> getErrorString("Parser.TOKEN.RARROW")
|
|
| Parser.TOKEN_RARROW2 -> getErrorString("Parser.TOKEN.RARROW2")
|
|
| Parser.TOKEN_SIG -> getErrorString("Parser.TOKEN.SIG")
|
|
| Parser.TOKEN_STRUCT -> getErrorString("Parser.TOKEN.STRUCT")
|
|
| Parser.TOKEN_UPCAST -> getErrorString("Parser.TOKEN.UPCAST")
|
|
| Parser.TOKEN_DOWNCAST -> getErrorString("Parser.TOKEN.DOWNCAST")
|
|
| Parser.TOKEN_NULL -> getErrorString("Parser.TOKEN.NULL")
|
|
| Parser.TOKEN_RESERVED -> getErrorString("Parser.TOKEN.RESERVED")
|
|
| Parser.TOKEN_MODULE -> getErrorString("Parser.TOKEN.MODULE")
|
|
| Parser.TOKEN_AND -> getErrorString("Parser.TOKEN.AND")
|
|
| Parser.TOKEN_AS -> getErrorString("Parser.TOKEN.AS")
|
|
| Parser.TOKEN_ASSERT -> getErrorString("Parser.TOKEN.ASSERT")
|
|
| Parser.TOKEN_ASR-> getErrorString("Parser.TOKEN.ASR")
|
|
| Parser.TOKEN_DOWNTO -> getErrorString("Parser.TOKEN.DOWNTO")
|
|
| Parser.TOKEN_EXCEPTION -> getErrorString("Parser.TOKEN.EXCEPTION")
|
|
| Parser.TOKEN_FALSE -> getErrorString("Parser.TOKEN.FALSE")
|
|
| Parser.TOKEN_FOR -> getErrorString("Parser.TOKEN.FOR")
|
|
| Parser.TOKEN_FUN -> getErrorString("Parser.TOKEN.FUN")
|
|
| Parser.TOKEN_FUNCTION-> getErrorString("Parser.TOKEN.FUNCTION")
|
|
| Parser.TOKEN_FINALLY -> getErrorString("Parser.TOKEN.FINALLY")
|
|
| Parser.TOKEN_LAZY -> getErrorString("Parser.TOKEN.LAZY")
|
|
| Parser.TOKEN_MATCH -> getErrorString("Parser.TOKEN.MATCH")
|
|
| Parser.TOKEN_METHOD -> getErrorString("Parser.TOKEN.METHOD")
|
|
| Parser.TOKEN_MUTABLE -> getErrorString("Parser.TOKEN.MUTABLE")
|
|
| Parser.TOKEN_NEW -> getErrorString("Parser.TOKEN.NEW")
|
|
| Parser.TOKEN_OF -> getErrorString("Parser.TOKEN.OF")
|
|
| Parser.TOKEN_OPEN -> getErrorString("Parser.TOKEN.OPEN")
|
|
| Parser.TOKEN_OR -> getErrorString("Parser.TOKEN.OR")
|
|
| Parser.TOKEN_VOID -> getErrorString("Parser.TOKEN.VOID")
|
|
| Parser.TOKEN_EXTERN-> getErrorString("Parser.TOKEN.EXTERN")
|
|
| Parser.TOKEN_INTERFACE -> getErrorString("Parser.TOKEN.INTERFACE")
|
|
| Parser.TOKEN_REC -> getErrorString("Parser.TOKEN.REC")
|
|
| Parser.TOKEN_TO -> getErrorString("Parser.TOKEN.TO")
|
|
| Parser.TOKEN_TRUE -> getErrorString("Parser.TOKEN.TRUE")
|
|
| Parser.TOKEN_TRY -> getErrorString("Parser.TOKEN.TRY")
|
|
| Parser.TOKEN_TYPE -> getErrorString("Parser.TOKEN.TYPE")
|
|
| Parser.TOKEN_VAL -> getErrorString("Parser.TOKEN.VAL")
|
|
| Parser.TOKEN_INLINE -> getErrorString("Parser.TOKEN.INLINE")
|
|
| Parser.TOKEN_WHEN -> getErrorString("Parser.TOKEN.WHEN")
|
|
| Parser.TOKEN_WHILE -> getErrorString("Parser.TOKEN.WHILE")
|
|
| Parser.TOKEN_WITH-> getErrorString("Parser.TOKEN.WITH")
|
|
| Parser.TOKEN_IF -> getErrorString("Parser.TOKEN.IF")
|
|
| Parser.TOKEN_DO -> getErrorString("Parser.TOKEN.DO")
|
|
| Parser.TOKEN_DONE -> getErrorString("Parser.TOKEN.DONE")
|
|
| Parser.TOKEN_IN -> getErrorString("Parser.TOKEN.IN")
|
|
| Parser.TOKEN_HIGH_PRECEDENCE_APP-> getErrorString("Parser.TOKEN.HIGH.PRECEDENCE.APP")
|
|
| Parser.TOKEN_BEGIN -> getErrorString("Parser.TOKEN.BEGIN")
|
|
| Parser.TOKEN_END -> getErrorString("Parser.TOKEN.END")
|
|
| Parser.TOKEN_HASH_LIGHT
|
|
| Parser.TOKEN_HASH_LINE
|
|
| Parser.TOKEN_HASH_IF
|
|
| Parser.TOKEN_HASH_ELSE
|
|
| Parser.TOKEN_HASH_ENDIF -> getErrorString("Parser.TOKEN.HASH.ENDIF")
|
|
| Parser.TOKEN_INACTIVECODE -> getErrorString("Parser.TOKEN.INACTIVECODE")
|
|
| Parser.TOKEN_LEX_FAILURE-> getErrorString("Parser.TOKEN.LEX.FAILURE")
|
|
| Parser.TOKEN_WHITESPACE -> getErrorString("Parser.TOKEN.WHITESPACE")
|
|
| Parser.TOKEN_COMMENT -> getErrorString("Parser.TOKEN.COMMENT")
|
|
| Parser.TOKEN_LINE_COMMENT -> getErrorString("Parser.TOKEN.LINE.COMMENT")
|
|
| Parser.TOKEN_STRING_TEXT -> getErrorString("Parser.TOKEN.STRING.TEXT")
|
|
| Parser.TOKEN_BYTEARRAY -> getErrorString("Parser.TOKEN.BYTEARRAY")
|
|
| Parser.TOKEN_STRING -> getErrorString("Parser.TOKEN.STRING")
|
|
| Parser.TOKEN_EOF -> getErrorString("Parser.TOKEN.EOF")
|
|
| unknown -> sprintf "%A" unknown
|
|
|
|
match ctxt.CurrentToken with
|
|
| None -> os.Append(UnexpectedEndOfInputE.Format) |> ignore
|
|
| Some token ->
|
|
match (token |> Parser.tagOfToken |> Parser.tokenTagToTokenId), token with
|
|
| (Parser.TOKEN_ORIGHT_BLOCK_END | Parser.TOKEN_OBLOCKEND),_ -> os.Append(OBlockEndE.Format) |> ignore
|
|
| Parser.TOKEN_LEX_FAILURE, Parser.LEX_FAILURE str -> Printf.bprintf os "%s" str (* Fix bug://2431 *)
|
|
| token,_ -> os.Append(UnexpectedE.Format (token |> tokenIdToText)) |> ignore
|
|
|
|
(* Search for a state producing a single recognized non-terminal in the states on the stack *)
|
|
let foundInContext =
|
|
|
|
(* Merge a bunch of expression non terminals *)
|
|
let (|NONTERM_Category_Expr|_|) = function
|
|
| Parser.NONTERM_argExpr|Parser.NONTERM_minusExpr|Parser.NONTERM_parenExpr|Parser.NONTERM_atomicExpr
|
|
| Parser.NONTERM_appExpr|Parser.NONTERM_tupleExpr|Parser.NONTERM_declExpr|Parser.NONTERM_braceExpr
|
|
| Parser.NONTERM_typedSeqExprBlock
|
|
| Parser.NONTERM_interactiveExpr -> Some()
|
|
| _ -> None
|
|
|
|
(* Merge a bunch of pattern non terminals *)
|
|
let (|NONTERM_Category_Pattern|_|) = function
|
|
| Parser.NONTERM_constrPattern|Parser.NONTERM_parenPattern|Parser.NONTERM_atomicPattern -> Some()
|
|
| _ -> None
|
|
|
|
(* Merge a bunch of if/then/else non terminals *)
|
|
let (|NONTERM_Category_IfThenElse|_|) = function
|
|
| Parser.NONTERM_ifExprThen|Parser.NONTERM_ifExprElifs|Parser.NONTERM_ifExprCases -> Some()
|
|
| _ -> None
|
|
|
|
(* Merge a bunch of non terminals *)
|
|
let (|NONTERM_Category_SignatureFile|_|) = function
|
|
| Parser.NONTERM_signatureFile|Parser.NONTERM_moduleSpfn|Parser.NONTERM_moduleSpfns -> Some()
|
|
| _ -> None
|
|
let (|NONTERM_Category_ImplementationFile|_|) = function
|
|
| Parser.NONTERM_implementationFile|Parser.NONTERM_fileNamespaceImpl|Parser.NONTERM_fileNamespaceImpls -> Some()
|
|
| _ -> None
|
|
let (|NONTERM_Category_Definition|_|) = function
|
|
| Parser.NONTERM_fileModuleImpl|Parser.NONTERM_moduleDefn|Parser.NONTERM_interactiveModuleDefns
|
|
|Parser.NONTERM_moduleDefns|Parser.NONTERM_moduleDefnsOrExpr -> Some()
|
|
| _ -> None
|
|
|
|
let (|NONTERM_Category_Type|_|) = function
|
|
| Parser.NONTERM_typ|Parser.NONTERM_tupleType -> Some()
|
|
| _ -> None
|
|
|
|
let (|NONTERM_Category_Interaction|_|) = function
|
|
| Parser.NONTERM_interactiveItemsTerminator|Parser.NONTERM_interaction|Parser.NONTERM__startinteraction -> Some()
|
|
| _ -> None
|
|
|
|
|
|
// Canonicalize the categories and check for a unique category
|
|
ctxt.ReducibleProductions |> List.exists (fun prods ->
|
|
match prods
|
|
|> List.map Parser.prodIdxToNonTerminal
|
|
|> List.map (function
|
|
| NONTERM_Category_Type -> Parser.NONTERM_typ
|
|
| NONTERM_Category_Expr -> Parser.NONTERM_declExpr
|
|
| NONTERM_Category_Pattern -> Parser.NONTERM_atomicPattern
|
|
| NONTERM_Category_IfThenElse -> Parser.NONTERM_ifExprThen
|
|
| NONTERM_Category_SignatureFile -> Parser.NONTERM_signatureFile
|
|
| NONTERM_Category_ImplementationFile -> Parser.NONTERM_implementationFile
|
|
| NONTERM_Category_Definition -> Parser.NONTERM_moduleDefn
|
|
| NONTERM_Category_Interaction -> Parser.NONTERM_interaction
|
|
| nt -> nt)
|
|
|> Set.of_list
|
|
|> Set.to_list with
|
|
| [Parser.NONTERM_interaction] -> os.Append(NONTERM_interactionE.Format) |> ignore; true
|
|
| [Parser.NONTERM_hashDirective] -> os.Append(NONTERM_hashDirectiveE.Format) |> ignore; true
|
|
| [Parser.NONTERM_fieldDecl] -> os.Append(NONTERM_fieldDeclE.Format) |> ignore; true
|
|
| [Parser.NONTERM_unionCaseRepr] -> os.Append(NONTERM_unionCaseReprE.Format) |> ignore; true
|
|
| [Parser.NONTERM_localBinding] -> os.Append(NONTERM_localBindingE.Format) |> ignore; true
|
|
| [Parser.NONTERM_hardwhiteLetBindings] -> os.Append(NONTERM_hardwhiteLetBindingsE.Format) |> ignore; true
|
|
| [Parser.NONTERM_classDefnMember] -> os.Append(NONTERM_classDefnMemberE.Format) |> ignore; true
|
|
| [Parser.NONTERM_defnBindings] -> os.Append(NONTERM_defnBindingsE.Format) |> ignore; true
|
|
| [Parser.NONTERM_classMemberSpfn] -> os.Append(NONTERM_classMemberSpfnE.Format) |> ignore; true
|
|
| [Parser.NONTERM_valSpfn] -> os.Append(NONTERM_valSpfnE.Format) |> ignore; true
|
|
| [Parser.NONTERM_tyconSpfn] -> os.Append(NONTERM_tyconSpfnE.Format) |> ignore; true
|
|
| [Parser.NONTERM_anonLambdaExpr] -> os.Append(NONTERM_anonLambdaExprE.Format) |> ignore; true
|
|
| [Parser.NONTERM_attrUnionCaseDecl] -> os.Append(NONTERM_attrUnionCaseDeclE.Format) |> ignore; true
|
|
| [Parser.NONTERM_cPrototype] -> os.Append(NONTERM_cPrototypeE.Format) |> ignore; true
|
|
| [Parser.NONTERM_objExpr|Parser.NONTERM_objectImplementationMembers] -> os.Append(NONTERM_objectImplementationMembersE.Format) |> ignore; true
|
|
| [Parser.NONTERM_ifExprThen|Parser.NONTERM_ifExprElifs|Parser.NONTERM_ifExprCases] -> os.Append(NONTERM_ifExprCasesE.Format) |> ignore; true
|
|
| [Parser.NONTERM_openDecl] -> os.Append(NONTERM_openDeclE.Format) |> ignore; true
|
|
| [Parser.NONTERM_fileModuleSpec] -> os.Append(NONTERM_fileModuleSpecE.Format) |> ignore; true
|
|
| [Parser.NONTERM_patternClauses] -> os.Append(NONTERM_patternClausesE.Format) |> ignore; true
|
|
| [Parser.NONTERM_beginEndExpr] -> os.Append(NONTERM_beginEndExprE.Format) |> ignore; true
|
|
| [Parser.NONTERM_recdExpr] -> os.Append(NONTERM_recdExprE.Format) |> ignore; true
|
|
| [Parser.NONTERM_tyconDefn] -> os.Append(NONTERM_tyconDefnE.Format) |> ignore; true
|
|
| [Parser.NONTERM_exconCore] -> os.Append(NONTERM_exconCoreE.Format) |> ignore; true
|
|
| [Parser.NONTERM_typeNameInfo] -> os.Append(NONTERM_typeNameInfoE.Format) |> ignore; true
|
|
| [Parser.NONTERM_attributeList] -> os.Append(NONTERM_attributeListE.Format) |> ignore; true
|
|
| [Parser.NONTERM_quoteExpr] -> os.Append(NONTERM_quoteExprE.Format) |> ignore; true
|
|
| [Parser.NONTERM_typeConstraint] -> os.Append(NONTERM_typeConstraintE.Format) |> ignore; true
|
|
| [NONTERM_Category_ImplementationFile] -> os.Append(NONTERM_Category_ImplementationFileE.Format) |> ignore; true
|
|
| [NONTERM_Category_Definition] -> os.Append(NONTERM_Category_DefinitionE.Format) |> ignore; true
|
|
| [NONTERM_Category_SignatureFile] -> os.Append(NONTERM_Category_SignatureFileE.Format) |> ignore; true
|
|
| [NONTERM_Category_Pattern] -> os.Append(NONTERM_Category_PatternE.Format) |> ignore; true
|
|
| [NONTERM_Category_Expr] -> os.Append(NONTERM_Category_ExprE.Format) |> ignore; true
|
|
| [NONTERM_Category_Type] -> os.Append(NONTERM_Category_TypeE.Format) |> ignore; true
|
|
| [Parser.NONTERM_typeArgsActual] -> os.Append(NONTERM_typeArgsActualE.Format) |> ignore; true
|
|
| _ ->
|
|
false)
|
|
#if DEBUG
|
|
if not foundInContext then
|
|
Printf.bprintf os ". (Please report to fsbugs@microsoft.com: no 'in' context found: %+A)" (List.map (List.map Parser.prodIdxToNonTerminal) ctxt.ReducibleProductions);
|
|
#endif
|
|
let fix (s:string) = s.Replace(SR.GetString("FixKeyword"),"").Replace(SR.GetString("FixSymbol"),"").Replace(SR.GetString("FixReplace"),"")
|
|
match (ctxt.ShiftTokens
|
|
|> List.map Parser.tokenTagToTokenId
|
|
|> List.filter (function Parser.TOKEN_error | Parser.TOKEN_EOF -> false | _ -> true)
|
|
|> List.map tokenIdToText
|
|
|> Set.of_list
|
|
|> Set.to_list) with
|
|
| [tokenName1] -> os.Append(TokenName1E.Format (fix tokenName1)) |> ignore
|
|
| [tokenName1;tokenName2] -> os.Append(TokenName1TokenName2E.Format (fix tokenName1) (fix tokenName2)) |> ignore
|
|
| [tokenName1;tokenName2;tokenName3] -> os.Append(TokenName1TokenName2TokenName3E.Format (fix tokenName1) (fix tokenName2) (fix tokenName3)) |> ignore
|
|
| _ -> ()
|
|
(*
|
|
Printf.bprintf os ".\n\n state = %A\n token = %A\n expect (shift) %A\n expect (reduce) %A\n prods=%A\n non terminals: %A"
|
|
ctxt.StateStack
|
|
ctxt.CurrentToken
|
|
(List.map Parser.tokenTagToTokenId ctxt.ShiftTokens)
|
|
(List.map Parser.tokenTagToTokenId ctxt.ReduceTokens)
|
|
ctxt.ReducibleProductions
|
|
(List.mapSquared Parser.prodIdxToNonTerminal ctxt.ReducibleProductions)
|
|
*)
|
|
| RuntimeCoercionSourceSealed(denv,ty,m) ->
|
|
let _,ty,tpcs = PrettyTypes.PrettifyTypes1 denv.g ty
|
|
if is_typar_typ denv.g ty
|
|
then os.Append(RuntimeCoercionSourceSealed1E.Format (NicePrint.string_of_typ denv ty)) |> ignore
|
|
else os.Append(RuntimeCoercionSourceSealed2E.Format (NicePrint.string_of_typ denv ty)) |> ignore
|
|
| CoercionTargetSealed(denv,ty,m) ->
|
|
let _,ty,tpcs = PrettyTypes.PrettifyTypes1 denv.g ty
|
|
os.Append(CoercionTargetSealedE.Format (NicePrint.string_of_typ denv ty)) |> ignore
|
|
| UpcastUnnecessary(m) ->
|
|
os.Append(UpcastUnnecessaryE.Format) |> ignore
|
|
| TypeTestUnnecessary(m) ->
|
|
os.Append(TypeTestUnnecessaryE.Format) |> ignore
|
|
| Creflect.IgnoringPartOfQuotedTermWarning (msg,_) ->
|
|
Printf.bprintf os "%s" msg
|
|
| OverrideDoesntOverride(denv,impl,minfoVirtOpt,g,amap,m) ->
|
|
let sig1 = DispatchSlotChecking.FormatOverride denv impl
|
|
begin match minfoVirtOpt with
|
|
| None ->
|
|
os.Append(OverrideDoesntOverride1E.Format sig1) |> ignore
|
|
| Some minfoVirt ->
|
|
os.Append(OverrideDoesntOverride2E.Format sig1) |> ignore
|
|
let sig2 = DispatchSlotChecking.FormatMethInfoSig g amap m denv minfoVirt
|
|
if sig1 <> sig2 then
|
|
os.Append(OverrideDoesntOverride3E.Format sig2) |> ignore
|
|
end
|
|
| UnionCaseWrongArguments (denv,n1,n2,m) ->
|
|
os.Append(UnionCaseWrongArgumentsE.Format n2 n1) |> ignore
|
|
| UnionPatternsBindDifferentNames m ->
|
|
os.Append(UnionPatternsBindDifferentNamesE.Format) |> ignore
|
|
| ValueNotContained (denv,mref,v1,v2,s) ->
|
|
let text1,text2 = minimalStringsOfTwoValues denv v1 v2
|
|
os.Append(ValueNotContainedE.Format
|
|
(full_display_text_of_modref mref)
|
|
text1
|
|
text2
|
|
s) |> ignore
|
|
| ConstrNotContained (denv,v1,v2,msg) ->
|
|
os.Append(ConstrNotContainedE.Format (NicePrint.string_of_ucase denv v1) (NicePrint.string_of_ucase denv v2) msg) |> ignore
|
|
| ExnconstrNotContained (denv,v1,v2,s) ->
|
|
os.Append(ExnconstrNotContainedE.Format s (NicePrint.string_of_exnc denv v1) (NicePrint.string_of_exnc denv v2)) |> ignore
|
|
| FieldNotContained (denv,v1,v2,msg) ->
|
|
os.Append(FieldNotContainedE.Format (NicePrint.string_of_rfield denv v1) (NicePrint.string_of_rfield denv v2) msg) |> ignore
|
|
| RequiredButNotSpecified (denv,mref,k,name,m) ->
|
|
let nsb = new System.Text.StringBuilder()
|
|
name nsb;
|
|
os.Append(RequiredButNotSpecifiedE.Format (full_display_text_of_modref mref) k (nsb.ToString())) |> ignore
|
|
| UseOfAddressOfOperator _ ->
|
|
os.Append(UseOfAddressOfOperatorE.Format) |> ignore
|
|
| DefensiveCopyWarning(s,m) -> os.Append(DefensiveCopyWarningE.Format s) |> ignore
|
|
| DeprecatedThreadStaticBindingWarning(m) ->
|
|
os.Append(DeprecatedThreadStaticBindingWarningE.Format) |> ignore
|
|
| DeprecatedClassFieldInference(m) ->
|
|
os.Append(DeprecatedClassFieldInferenceE.Format) |> ignore
|
|
| FunctionValueUnexpected (denv,ty,m) ->
|
|
let _,ty,tpcs = PrettyTypes.PrettifyTypes1 denv.g ty
|
|
os.Append(FunctionValueUnexpectedE.Format (NicePrint.string_of_typ denv ty)) |> ignore
|
|
| UnitTypeExpected (denv,ty,perhapsProp,m) ->
|
|
let _,ty,tpcs = PrettyTypes.PrettifyTypes1 denv.g ty
|
|
os.Append(UnitTypeExpected1E.Format (NicePrint.string_of_typ denv ty)) |> ignore
|
|
if perhapsProp then os.Append(UnitTypeExpected2E.Format) |> ignore
|
|
| RecursiveUseCheckedAtRuntime (denv,v,m) ->
|
|
os.Append(RecursiveUseCheckedAtRuntimeE.Format) |> ignore
|
|
| LetRecUnsound (denv,[v],m) ->
|
|
os.Append(LetRecUnsound1E.Format v.DisplayName) |> ignore
|
|
| LetRecUnsound (denv,path,m) ->
|
|
let bos = new System.Text.StringBuilder()
|
|
let s = List.iter (fun (v:ValRef) -> bos.Append(LetRecUnsoundInnerE.Format v.DisplayName) |> ignore) (List.tl path @ [List.hd path])
|
|
os.Append(LetRecUnsound2E.Format (List.hd path).DisplayName (bos.ToString())) |> ignore
|
|
| LetRecEvaluatedOutOfOrder (denv,v1,v2,m) ->
|
|
os.Append(LetRecEvaluatedOutOfOrderE.Format) |> ignore
|
|
| LetRecCheckedAtRuntime _ ->
|
|
os.Append(LetRecCheckedAtRuntimeE.Format) |> ignore
|
|
| SelfRefObjCtor(false,m) ->
|
|
os.Append(SelfRefObjCtor1E.Format) |> ignore
|
|
| SelfRefObjCtor(true,m) ->
|
|
os.Append(SelfRefObjCtor2E.Format) |> ignore
|
|
| VirtualAugmentationOnNullValuedType(m) ->
|
|
os.Append(VirtualAugmentationOnNullValuedTypeE.Format) |> ignore
|
|
| NonVirtualAugmentationOnNullValuedType(m) ->
|
|
os.Append(NonVirtualAugmentationOnNullValuedTypeE.Format) |> ignore
|
|
| NonUniqueInferredAbstractSlot(g,denv,bindnm,bvirt1,bvirt2,m) ->
|
|
os.Append(NonUniqueInferredAbstractSlot1E.Format bindnm) |> ignore
|
|
let ty1 = bvirt1.EnclosingType
|
|
let ty2 = bvirt2.EnclosingType
|
|
let t1,t2,tpcs = minimalStringsOfTwoTypes denv ty1 ty2
|
|
os.Append(NonUniqueInferredAbstractSlot2E.Format) |> ignore
|
|
if t1 <> t2 then
|
|
os.Append(NonUniqueInferredAbstractSlot3E.Format t1 t2) |> ignore
|
|
os.Append(NonUniqueInferredAbstractSlot4E.Format) |> ignore
|
|
| Error (s,m) -> os.Append(ErrorE.Format s) |> ignore
|
|
| InternalError (s,_)
|
|
| InvalidArgument s
|
|
| Failure s ->
|
|
let f1 = SR.GetString("Failure1")
|
|
let f2 = SR.GetString("Failure2")
|
|
match s with
|
|
| f when f = f1 -> os.Append(Failure3E.Format s) |> ignore
|
|
| f when f = f2 -> os.Append(Failure3E.Format s) |> ignore
|
|
| _ -> os.Append(Failure4E.Format s) |> ignore
|
|
#if DEBUG
|
|
Printf.bprintf os "\nStack Trace\n%s\n" (exn.ToString())
|
|
if !showAssertForUnexpectedException then
|
|
System.Diagnostics.Debug.Assert(false,sprintf "Bug seen in compiler: %s" (exn.ToString()))
|
|
#endif
|
|
| FullAbstraction(s,m) -> os.Append(FullAbstractionE.Format s) |> ignore
|
|
| WrappedError (exn,m) -> OutputExceptionR os exn
|
|
| Patcompile.MatchIncomplete (isComp,cexOpt,m) ->
|
|
os.Append(MatchIncomplete1E.Format) |> ignore
|
|
match cexOpt with
|
|
| None -> ()
|
|
| Some (cex,false) -> os.Append(MatchIncomplete2E.Format cex) |> ignore
|
|
| Some (cex,true) -> os.Append(MatchIncomplete3E.Format cex) |> ignore
|
|
if isComp then
|
|
os.Append(MatchIncomplete4E.Format) |> ignore
|
|
| Patcompile.RuleNeverMatched m -> os.Append(RuleNeverMatchedE.Format) |> ignore
|
|
| ValNotMutable(denv,vr,m) -> os.Append(ValNotMutableE.Format) |> ignore
|
|
| ValNotLocal(denv,vr,m) -> os.Append(ValNotLocalE.Format) |> ignore
|
|
| Obsolete (s, _) ->
|
|
os.Append(Obsolete1E.Format) |> ignore
|
|
if s <> "" then os.Append(Obsolete2E.Format s) |> ignore
|
|
| Experimental (s, _) -> os.Append(ExperimentalE.Format s) |> ignore
|
|
| PossibleUnverifiableCode m -> os.Append(PossibleUnverifiableCodeE.Format) |> ignore
|
|
| OCamlCompatibility (s, _) -> os.Append(OCamlCompatibilityE.Format (if s = "" then "" else s^". ")) |> ignore
|
|
| Deprecated(s, _) -> os.Append(DeprecatedE.Format s) |> ignore
|
|
| LibraryUseOnly(_) -> os.Append(LibraryUseOnlyE.Format) |> ignore
|
|
| MissingFields(sl,m) -> os.Append(MissingFieldsE.Format (String.concat "," sl ^".")) |> ignore
|
|
| ValueRestriction(denv,hassig,v,tp,m) ->
|
|
let denv = { denv with showImperativeTyparAnnotations=true; }
|
|
let tps,tau = v.TypeScheme
|
|
if hassig then
|
|
if is_fun_typ denv.g tau && (arity_of_val v).HasNoArgs then
|
|
os.Append(ValueRestriction1E.Format
|
|
v.DisplayName
|
|
(NicePrint.string_of_qualified_val_spec denv v)
|
|
v.DisplayName) |> ignore
|
|
else
|
|
os.Append(ValueRestriction2E.Format
|
|
v.DisplayName
|
|
(NicePrint.string_of_qualified_val_spec denv v)
|
|
v.DisplayName) |> ignore
|
|
else
|
|
match v.MemberInfo with
|
|
| Some(membInfo) when
|
|
begin match membInfo.MemberFlags.MemberKind with
|
|
| MemberKindPropertyGet
|
|
| MemberKindPropertySet
|
|
| MemberKindConstructor -> true (* can't infer extra polymorphism *)
|
|
| _ -> false (* can infer extra polymorphism *)
|
|
end ->
|
|
os.Append(ValueRestriction3E.Format (NicePrint.string_of_qualified_val_spec denv v)) |> ignore
|
|
| _ ->
|
|
if is_fun_typ denv.g tau && (arity_of_val v).HasNoArgs then
|
|
os.Append(ValueRestriction4E.Format
|
|
v.DisplayName
|
|
(NicePrint.string_of_qualified_val_spec denv v)
|
|
v.DisplayName) |> ignore
|
|
else
|
|
os.Append(ValueRestriction5E.Format
|
|
v.DisplayName
|
|
(NicePrint.string_of_qualified_val_spec denv v)
|
|
v.DisplayName) |> ignore
|
|
|
|
| Parsing.RecoverableParseError -> os.Append(RecoverableParseErrorE.Format) |> ignore
|
|
| ReservedKeyword (s,m) -> os.Append(ReservedKeywordE.Format s) |> ignore
|
|
| IndentationProblem (s,m) -> os.Append(IndentationProblemE.Format s) |> ignore
|
|
| OverrideInIntrinsicAugmentation(m) -> os.Append(OverrideInIntrinsicAugmentationE.Format) |> ignore
|
|
| OverrideInExtrinsicAugmentation(m) -> os.Append(OverrideInExtrinsicAugmentationE.Format) |> ignore
|
|
| IntfImplInIntrinsicAugmentation(m) -> os.Append(IntfImplInIntrinsicAugmentationE.Format) |> ignore
|
|
| IntfImplInExtrinsicAugmentation(m) -> os.Append(IntfImplInExtrinsicAugmentationE.Format) |> ignore
|
|
| UnresolvedReferenceError(assemblyname,_)
|
|
| UnresolvedReferenceNoRange(assemblyname) ->
|
|
os.Append(UnresolvedReferenceNoRangeE.Format assemblyname) |> ignore
|
|
| UnresolvedPathReference(assemblyname,pathname,_)
|
|
| UnresolvedPathReferenceNoRange(assemblyname,pathname) ->
|
|
os.Append(UnresolvedPathReferenceNoRangeE.Format pathname assemblyname) |> ignore
|
|
| DeprecatedCommandLineOption(optionName,altOption,_) -> os.Append(DeprecatedCommandLineOptionE.Format optionName altOption) |> ignore
|
|
| HashIncludeNotAllowedInNonScript(_) ->
|
|
os.Append(HashIncludeNotAllowedInNonScriptE.Format) |> ignore
|
|
| HashReferenceNotAllowedInNonScript(_) ->
|
|
os.Append(HashReferenceNotAllowedInNonScriptE.Format) |> ignore
|
|
| HashReferenceCopyAfterCompileNotAllowedInNonScript(_) ->
|
|
os.Append(HashReferenceCopyAfterCompileNotAllowedInNonScriptE.Format) |> ignore
|
|
| HashDirectiveNotAllowedInNonScript(_) ->
|
|
os.Append(HashDirectiveNotAllowedInNonScriptE.Format) |> ignore
|
|
| FileNameNotResolved(filename,locations,_) ->
|
|
os.Append(FileNameNotResolvedE.Format filename locations) |> ignore
|
|
| AssemblyNotResolved(originalName,_) ->
|
|
os.Append(AssemblyNotResolvedE.Format originalName) |> ignore
|
|
| HashLoadedSourceHasIssues(warnings,errors,_) ->
|
|
let Emit(l:exn list) =
|
|
OutputExceptionR os (List.hd l)
|
|
if errors=[] then
|
|
os.Append(HashLoadedSourceHasIssues1E.Format) |> ignore
|
|
Emit(warnings)
|
|
else
|
|
os.Append(HashLoadedSourceHasIssues2E.Format) |> ignore
|
|
Emit(errors)
|
|
| HashLoadedScriptConsideredSource(_) ->
|
|
os.Append(HashLoadedScriptConsideredSourceE.Format) |> ignore
|
|
| InvalidInternalsVisibleToAssemblyName(badName,fileNameOption) ->
|
|
match fileNameOption with
|
|
| Some file -> os.Append(InvalidInternalsVisibleToAssemblyName1E.Format badName file) |> ignore
|
|
| None -> os.Append(InvalidInternalsVisibleToAssemblyName2E.Format badName) |> ignore
|
|
| LoadedSourceNotFoundIgnoring(filename,_) ->
|
|
os.Append(LoadedSourceNotFoundIgnoringE.Format filename) |> ignore
|
|
| MSBuildReferenceResolutionWarning(code,message,_)
|
|
| MSBuildReferenceResolutionError(code,message,_) ->
|
|
os.Append(MSBuildReferenceResolutionErrorE.Format message code) |> ignore
|
|
// Strip TargetInvocationException wrappers
|
|
| :? System.Reflection.TargetInvocationException as e ->
|
|
OutputExceptionR os e.InnerException
|
|
| :? FileNotFoundException as e -> Printf.bprintf os "%s" e.Message
|
|
| :? DirectoryNotFoundException as e -> Printf.bprintf os "%s" e.Message
|
|
| :? System.ArgumentException as e -> Printf.bprintf os "%s" e.Message
|
|
| :? System.NotSupportedException as e -> Printf.bprintf os "%s" e.Message
|
|
| :? IOException as e -> Printf.bprintf os "%s" e.Message
|
|
| :? System.UnauthorizedAccessException as e -> Printf.bprintf os "%s" e.Message
|
|
| e ->
|
|
os.Append(TargetInvocationExceptionWrapperE.Format e.Message) |> ignore
|
|
#if DEBUG
|
|
Printf.bprintf os "\nStack Trace\n%s\n" (exn.ToString())
|
|
if !showAssertForUnexpectedException then
|
|
System.Diagnostics.Debug.Assert(false,sprintf "Bug seen in compiler: %s" (exn.ToString()))
|
|
#endif
|
|
|
|
|
|
and output_plural os n = if n <> 1 then Printf.bprintf os "s"
|
|
|
|
// remove any newlines and tabs
|
|
let OutputException (os:System.Text.StringBuilder) exn (flattenErrors:bool) =
|
|
let buf = new System.Text.StringBuilder()
|
|
|
|
OutputExceptionR buf exn
|
|
|
|
let s = if flattenErrors then buf.ToString().Replace('\n',' ').Replace('\t',' ') else buf.ToString()
|
|
|
|
os.Append(s) |> ignore
|
|
|
|
|
|
type ErrorStyle =
|
|
| DefaultErrors
|
|
| EmacsErrors
|
|
| TestErrors
|
|
| VSErrors
|
|
|
|
let SanitizeFileName fileName implicitIncludeDir =
|
|
// The assert below is almost ok, but it fires in two cases:
|
|
// - fsi.exe sometimes passes "stdin" as a dummy filename
|
|
// - if you have a #line directive, e.g.
|
|
// # 1000 "Line01.fs"
|
|
// then it also asserts. But these are edge cases that can be fixed later, e.g. in bug 4651.
|
|
//System.Diagnostics.Debug.Assert(System.IO.Path.IsPathRooted(fileName), sprintf "filename should be absolute: '%s'" fileName)
|
|
let fullPath = System.IO.Path.GetFullPath(fileName)
|
|
let currentDir = implicitIncludeDir
|
|
|
|
// if the file name is not rooted in the current directory, return the full path
|
|
if not(fullPath.StartsWith(currentDir)) then
|
|
fullPath
|
|
// if the file name is rooted in the current directory, return the relative path
|
|
else
|
|
fullPath.Replace(currentDir^"\\","")
|
|
|
|
(* used by fsc.exe and fsi.exe, but not by VS *)
|
|
let rec OutputErrorOrWarning (implicitIncludeDir,showFullPaths,flattenErrors,errorStyle,warn) os (err:exn) =
|
|
let output_where (showFullPaths,errorStyle) exn os m =
|
|
if m = rangeStartup || m = rangeCmdArgs then ()
|
|
else
|
|
let file = file_of_range m
|
|
let file = if showFullPaths then
|
|
Filename.fullpath implicitIncludeDir file
|
|
else
|
|
SanitizeFileName file implicitIncludeDir
|
|
match errorStyle with
|
|
| ErrorStyle.EmacsErrors -> Printf.bprintf os "File \"%s\", line %d, characters %d-%d: " (file.Replace("\\","/")) (start_line_of_range m) (start_col_of_range m) (end_col_of_range m)
|
|
// We're adjusting the columns here to be 1-based - both for parity with C# and for MSBuild, which assumes 1-based columns for error output
|
|
| ErrorStyle.DefaultErrors -> Printf.bprintf os "%s(%d,%d): " (file.Replace("/","\\")) (start_line_of_range m) ((start_col_of_range m) + 1)
|
|
// We may also want to change TestErrors to be 1-based
|
|
| ErrorStyle.TestErrors -> Printf.bprintf os "%s(%d,%d-%d,%d): " (file.Replace("/","\\")) (start_line_of_range m) ((start_col_of_range m) + 1) (end_line_of_range m) ((end_col_of_range m) + 1)
|
|
// Here, we want the complete range information so Project Systems can generate proper squiggles
|
|
| ErrorStyle.VSErrors -> Printf.bprintf os "%s(%d,%d,%d,%d): " (file.Replace("/","\\")) (start_line_of_range m) ((start_col_of_range m) + 1) (end_line_of_range m) ((end_col_of_range m) + 1)
|
|
|
|
|
|
match err with
|
|
| ReportedError ->
|
|
dprintf "Unexpected ReportedError" (* this should actually never happen *)
|
|
| StopProcessing ->
|
|
dprintf "Unexpected StopProcessing" (* this should actually never happen *)
|
|
| _ ->
|
|
Printf.bprintf os "\n";
|
|
match RangeOfError err with
|
|
| Some m -> output_where (showFullPaths,errorStyle) err os m
|
|
| None -> ()
|
|
|
|
Printf.bprintf os "%s FS%04d: " (if warn then "warning" else "error") (GetErrorNumber err);
|
|
let mainError,relatedErrors = SplitRelatedErrors err
|
|
OutputException os mainError flattenErrors;
|
|
List.iter (fun err -> Printf.bprintf os "\n"; OutputException os err flattenErrors) relatedErrors
|
|
|
|
let OutputErrorOrWarningContext prefix fileLineFn os (err:exn) =
|
|
match RangeOfError err with
|
|
| None -> ()
|
|
| Some m ->
|
|
let filename = file_of_range m
|
|
let lineA = start_line_of_range m
|
|
let lineB = end_line_of_range m
|
|
let line = fileLineFn filename lineA
|
|
if line<>"" then
|
|
let iA = start_col_of_range m
|
|
let iB = end_col_of_range m
|
|
let iLen = if lineA = lineB then max (iB - iA) 1 else 1
|
|
Printf.bprintf os "%s%s\n" prefix line;
|
|
Printf.bprintf os "%s%s%s\n" prefix (String.make iA '-') (String.make iLen '^')
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
let coreFramework =
|
|
[ "System";
|
|
"System.Xml" ]
|
|
|
|
let extendedFramework =
|
|
[ "System.Runtime.Remoting";
|
|
"System.Runtime.Serialization.Formatters.Soap";
|
|
"System.Data";
|
|
"System.Drawing";
|
|
"System.Web";
|
|
"System.Web.Services";
|
|
"System.Windows.Forms"; ]
|
|
|
|
let GetFSharpCoreLibraryName () = "FSharp.Core"
|
|
let GetFSharpPowerPackLibraryName () = "FSharp.PowerPack"
|
|
let fsiaux () = "FSharp.Compiler.Interactive.Settings"
|
|
let fsiAuxSettingsModulePath = "Microsoft.FSharp.Compiler.Interactive.Settings"
|
|
let scriptingFramework = coreFramework @ extendedFramework @ ["FSharp.Compiler.Interactive.Settings"]
|
|
|
|
let (++) x s = x @ [s]
|
|
|
|
/// Determine the default "frameworkVersion" (which is passed into MSBuild resolve).
|
|
/// If this binary was built for v4, the return "v4.0"
|
|
/// If this binary was built for v2, the return "v3.5", "v3.5" or "v2.0" depending on what is installed.
|
|
///
|
|
/// See: Detecting which versions of the .NET framework are installed.
|
|
/// http://blogs.msdn.com/aaronru/archive/2007/11/26/net-framework-3-5-rtm-detection-logic.aspx
|
|
/// See: bug 4409.
|
|
open Microsoft.Win32
|
|
let highestInstalledNetFrameworkVersionMajorMinor() =
|
|
#if FX_ATLEAST_40
|
|
4,"v4.0"
|
|
#else
|
|
try
|
|
let net35 = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.5","Install",null) = box 1
|
|
let net30 = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v3.0","Install",null) = box 1
|
|
let net20 = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727","Install",null) = box 1
|
|
if net35 then 2,"v3.5"
|
|
elif net30 then 2,"v3.0"
|
|
else 2,"v2.0" // version is 2.0 assumed since this code is running.
|
|
// the above calls to Registry.GetValue could potentially fail - especially on platforms like Mono
|
|
with e -> warning(Error("Could not determine highest installed .NET framework version from Registry keys, using version 2.0",rangeStartup)); 2,"v2.0"
|
|
#endif
|
|
|
|
//----------------------------------------------------------------------------
|
|
// General file name resolver
|
|
//--------------------------------------------------------------------------
|
|
|
|
let TryResolveFileUsingPaths(paths,m,name) =
|
|
let () =
|
|
try Path.IsPathRooted(name) |> ignore
|
|
with :? System.ArgumentException as e -> error(Error(e.Message,m))
|
|
if Path.IsPathRooted(name) && Internal.Utilities.FileSystem.File.SafeExists name
|
|
then name
|
|
else
|
|
let res = paths |> List.tryPick (fun path ->
|
|
let n = Filename.concat path name
|
|
if Internal.Utilities.FileSystem.File.SafeExists n then Some n
|
|
else None)
|
|
match res with
|
|
| Some f -> f
|
|
| None ->
|
|
let filename = name
|
|
let searchMessage = String.concat "\n " paths
|
|
raise (FileNameNotResolved(name,searchMessage,m))
|
|
|
|
|
|
|
|
let GetWarningNumber(m,s:string) =
|
|
try
|
|
Some (int32 s)
|
|
with err ->
|
|
warning(Error("invalid warning number: '"^s^"'",m));
|
|
None
|
|
|
|
let ComputeMakePathAbsolute implicitIncludeDir (path : string) =
|
|
try
|
|
// remove any quotation marks from the path first
|
|
let path = path.Replace("\"","")
|
|
if not (Path.IsPathRooted(path))
|
|
then Filename.concat implicitIncludeDir path
|
|
else path
|
|
with
|
|
:? System.ArgumentException -> path
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Configuration
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
/// Determins whether a path is invalid or not.
|
|
let IsInvalidPath (path : string) =
|
|
String.IsNullOrEmpty(path) ||
|
|
path.IndexOfAny(Path.GetInvalidPathChars()) <> -1
|
|
|
|
type target =
|
|
| WinExe
|
|
| ConsoleExe
|
|
| Dll
|
|
| Module
|
|
member x.IsExe = (match x with ConsoleExe | WinExe -> true | _ -> false)
|
|
|
|
type ResolveLibFileMode = Speculative | ReportErrors
|
|
|
|
type VersionFlag =
|
|
| VersionString of string
|
|
| VersionFile of string
|
|
| VersionNone
|
|
member x.GetVersionInfo(implicitIncludeDir) =
|
|
let vstr = x.GetVersionString(implicitIncludeDir)
|
|
try
|
|
IL.parse_version vstr
|
|
with _ -> errorR(Error("Invalid version string '"^vstr^"'",rangeStartup)) ; IL.parse_version "0.0.0.0"
|
|
|
|
member x.GetVersionString(implicitIncludeDir) =
|
|
match x with
|
|
| VersionString s -> s
|
|
| VersionFile s ->
|
|
let s = if Path.IsPathRooted(s) then s else Path.Combine(implicitIncludeDir,s)
|
|
if not(Internal.Utilities.FileSystem.File.SafeExists(s)) then
|
|
errorR(Error("Invalid version file '"^s^"'",rangeStartup)) ; "0.0.0.0"
|
|
else
|
|
use is = System.IO.File.OpenText s
|
|
is.ReadLine()
|
|
| VersionNone -> "0.0.0.0"
|
|
|
|
|
|
type AssemblyReference =
|
|
| AssemblyReference of range * string
|
|
member x.Range = (let (AssemblyReference(m,_)) = x in m)
|
|
member x.Text = (let (AssemblyReference(_,text)) = x in text)
|
|
member x.SimpleAssemblyNameIs(name) =
|
|
(String.Compare(Path.GetFileNameWithoutExtension(x.Text), name, StringComparison.OrdinalIgnoreCase) = 0) ||
|
|
(let text = x.Text.ToLowerInvariant()
|
|
not (text.Contains "/") && not (text.Contains "\\") && not (text.Contains ".dll") && not (text.Contains ".exe") &&
|
|
try let aname = System.Reflection.AssemblyName(x.Text) in aname.Name = name
|
|
with _ -> false)
|
|
|
|
type TcConfigBuilder =
|
|
{ mutable mscorlibAssemblyName : string;
|
|
mutable autoResolveOpenDirectivesToDlls: bool;
|
|
mutable noFeedback: bool;
|
|
mutable implicitIncludeDir: string; (* normally "." *)
|
|
mutable openBinariesInMemory: bool; (* false for command line, true for VS *)
|
|
mutable openDebugInformationForLaterStaticLinking: bool; (* only for --standalone *)
|
|
defaultFSharpBinariesDir: string;
|
|
mutable compilingFslib: bool;
|
|
mutable useIncrementalBuilder: bool;
|
|
mutable includes: string list;
|
|
mutable implicitOpens: string list;
|
|
mutable useFsiAuxLib: bool;
|
|
mutable framework: bool;
|
|
mutable resolutionEnvironment : ResolutionEnvironment
|
|
mutable implicitlyResolveAssemblies: bool;
|
|
mutable light: bool option;
|
|
mutable conditionalCompilationDefines: string list;
|
|
mutable loadedSources: (range * string) list;
|
|
mutable referencedDLLs : AssemblyReference list;
|
|
optimizeForMemory: bool;
|
|
mutable inputCodePage: int option;
|
|
mutable embedResources : string list;
|
|
mutable globalWarnAsError: bool;
|
|
mutable globalWarnLevel: int;
|
|
mutable specificWarnOff: int list;
|
|
mutable specificWarnAsError: int list
|
|
mutable mlCompatibility: bool;
|
|
mutable checkOverflow: bool;
|
|
mutable showReferenceResolutions:bool;
|
|
mutable outputFile : string option;
|
|
mutable resolutionFrameworkRegistryBase : string;
|
|
mutable resolutionAssemblyFoldersSuffix : string;
|
|
mutable resolutionAssemblyFoldersConditions : string;
|
|
mutable platform : ILPlatform option;
|
|
mutable useMonoResolution : bool
|
|
mutable target : target
|
|
mutable debuginfo : bool
|
|
mutable debugSymbolFile : string option
|
|
(* Backend configuration *)
|
|
mutable typeCheckOnly : bool
|
|
mutable parseOnly : bool
|
|
mutable simulateException : string option
|
|
mutable printAst : bool
|
|
mutable tokenizeOnly : bool
|
|
mutable testInteractionParser : bool
|
|
mutable reportNumDecls : bool
|
|
mutable printSignature : bool
|
|
mutable printSignatureFile : string
|
|
mutable xmlDocOutputFile : string option
|
|
mutable generateHtmlDocs : bool
|
|
mutable htmlDocDirectory : string option
|
|
mutable htmlDocCssFile : string option
|
|
mutable htmlDocNamespaceFile : string option
|
|
mutable htmlDocAppendFlag : bool
|
|
mutable htmlDocLocalLinks : bool (* Do not do absolute links for fslib/mllib references *)
|
|
mutable stats : bool
|
|
mutable generateFilterBlocks : bool (* don't generate filter blocks due to bugs on Mono *)
|
|
|
|
mutable signer : string option
|
|
mutable container : string option
|
|
|
|
mutable delaysign : bool
|
|
mutable version : VersionFlag
|
|
mutable standalone : bool
|
|
mutable extraStaticLinkRoots : string list
|
|
mutable noSignatureData : bool
|
|
mutable onlyEssentialOptimizationData : bool
|
|
mutable useOptimizationDataFile : bool
|
|
mutable jitTracking : bool
|
|
mutable ignoreSymbolStoreSequencePoints : bool
|
|
mutable internConstantStrings : bool
|
|
mutable generateConfigFile : bool
|
|
mutable extraOptimizationIterations : int
|
|
|
|
mutable win32res : string
|
|
mutable win32manifest : string
|
|
mutable includewin32manifest : bool
|
|
mutable linkResources : string list
|
|
|
|
|
|
mutable showFullPaths : bool
|
|
mutable errorStyle : ErrorStyle
|
|
mutable utf8output : bool
|
|
mutable flatErrors: bool
|
|
|
|
mutable maxErrors : int
|
|
mutable abortOnError : bool (* intended for fsi scripts that should exit on first error *)
|
|
mutable baseAddress : int32 option
|
|
#if DEBUG
|
|
mutable writeGeneratedILFiles : bool (* write il files? *)
|
|
mutable showOptimizationData : bool
|
|
#endif
|
|
mutable showTerms : bool (* show terms between passes? *)
|
|
mutable writeTermsToFiles : bool (* show terms to files? *)
|
|
mutable doDetuple : bool (* run detuple pass? *)
|
|
mutable doTLR : bool (* run TLR pass? - not by default *)
|
|
mutable optsOn : bool (* optimizations are turned on *)
|
|
mutable optSettings : Opt.OptimizationSettings
|
|
|
|
mutable product : string
|
|
/// show the MS (c) notice, e.g. with help or fsi?
|
|
mutable showBanner : bool
|
|
|
|
/// show times between passes?
|
|
mutable showTimes : bool
|
|
|
|
/// pause between passes?
|
|
mutable pause : bool
|
|
}
|
|
|
|
|
|
static member CreateNew (defaultFSharpBinariesDir,optimizeForMemory,implicitIncludeDir) =
|
|
System.Diagnostics.Debug.Assert(Path.IsPathRooted(implicitIncludeDir), sprintf "implicitIncludeDir should be absolute: '%s'" implicitIncludeDir)
|
|
if (String.IsNullOrEmpty(defaultFSharpBinariesDir)) then
|
|
failwith "Expected a valid defaultFSharpBinariesDir"
|
|
{ mscorlibAssemblyName = "mscorlib";
|
|
light = None;
|
|
noFeedback=false;
|
|
conditionalCompilationDefines=[];
|
|
implicitIncludeDir = implicitIncludeDir;
|
|
autoResolveOpenDirectivesToDlls = false;
|
|
openBinariesInMemory = false;
|
|
openDebugInformationForLaterStaticLinking=false;
|
|
defaultFSharpBinariesDir=defaultFSharpBinariesDir;
|
|
compilingFslib=false;
|
|
useIncrementalBuilder=false;
|
|
useFsiAuxLib=false;
|
|
implicitOpens=[];
|
|
includes=[];
|
|
resolutionEnvironment=MSBuildResolver.CompileTimeLike
|
|
framework=true;
|
|
implicitlyResolveAssemblies=true;
|
|
referencedDLLs = [];
|
|
loadedSources = [];
|
|
globalWarnAsError=false;
|
|
globalWarnLevel=3;
|
|
specificWarnOff=[];
|
|
specificWarnAsError=[]
|
|
embedResources = [];
|
|
inputCodePage=None;
|
|
optimizeForMemory=optimizeForMemory;
|
|
mlCompatibility=false;
|
|
checkOverflow=false;
|
|
showReferenceResolutions=false;
|
|
outputFile=None;
|
|
resolutionFrameworkRegistryBase = "Software\Microsoft\.NetFramework";
|
|
resolutionAssemblyFoldersSuffix = "AssemblyFoldersEx";
|
|
resolutionAssemblyFoldersConditions = "";
|
|
platform = None;
|
|
useMonoResolution = runningOnMono
|
|
target = ConsoleExe
|
|
debuginfo = false
|
|
debugSymbolFile = None
|
|
|
|
(* Backend configuration *)
|
|
typeCheckOnly = false
|
|
parseOnly = false
|
|
simulateException = None
|
|
printAst = false
|
|
tokenizeOnly = false
|
|
testInteractionParser = false
|
|
reportNumDecls = false
|
|
printSignature = false
|
|
printSignatureFile = ""
|
|
xmlDocOutputFile = None
|
|
generateHtmlDocs = false
|
|
htmlDocDirectory = None
|
|
htmlDocCssFile = None
|
|
htmlDocNamespaceFile = None
|
|
htmlDocAppendFlag = false
|
|
htmlDocLocalLinks = false (* Do not do absolute links for fslib/mllib references *)
|
|
stats = false
|
|
generateFilterBlocks = false (* don't generate filter blocks due to bugs on Mono *)
|
|
|
|
signer = None
|
|
container = None
|
|
maxErrors = 100
|
|
abortOnError = false
|
|
baseAddress = None
|
|
|
|
delaysign = false
|
|
version = VersionNone
|
|
standalone = false
|
|
extraStaticLinkRoots = []
|
|
noSignatureData = false
|
|
onlyEssentialOptimizationData = false
|
|
useOptimizationDataFile = false
|
|
jitTracking = true
|
|
ignoreSymbolStoreSequencePoints = false
|
|
internConstantStrings = true
|
|
generateConfigFile = false
|
|
extraOptimizationIterations = 0
|
|
|
|
win32res = ""
|
|
win32manifest = ""
|
|
includewin32manifest = true
|
|
linkResources = []
|
|
showFullPaths =false
|
|
errorStyle = ErrorStyle.DefaultErrors
|
|
utf8output = false
|
|
flatErrors = false
|
|
|
|
#if DEBUG
|
|
writeGeneratedILFiles = false (* write il files? *)
|
|
showOptimizationData = false
|
|
#endif
|
|
showTerms = false
|
|
writeTermsToFiles = false
|
|
|
|
doDetuple = false
|
|
doTLR = false
|
|
optsOn = false
|
|
optSettings = Opt.OptimizationSettings.Defaults
|
|
product = "Microsoft F# Compiler"
|
|
showBanner = true
|
|
showTimes = false
|
|
pause = false
|
|
}
|
|
/// Decide names of output file, pdb and assembly
|
|
member tcConfigB.DecideNames sourceFiles =
|
|
if sourceFiles = [] then errorR(Error("No inputs specified",rangeCmdArgs));
|
|
let ext() = match tcConfigB.target with Dll -> ".dll" | Module -> ".netmodule" | ConsoleExe | WinExe -> ".exe"
|
|
let implFiles = sourceFiles |> List.filter (fun lower -> List.exists (Filename.check_suffix (String.lowercase lower)) implSuffixes)
|
|
let outfile =
|
|
match tcConfigB.outputFile, List.rev implFiles with
|
|
| None,[] -> "out" ^ ext()
|
|
| None, h :: _ ->
|
|
let basic = Path.GetFileName h
|
|
let modname = try Filename.chop_extension basic with _ -> basic
|
|
modname^(ext())
|
|
| Some f,_ -> f
|
|
let assemblyName =
|
|
let baseName = Path.GetFileName outfile
|
|
if not (Filename.check_suffix (String.lowercase baseName) (ext())) then
|
|
errorR(Error("The output name extension doesn't match the flags used. If -a is used the output file name must end with .dll, if --target module is used the output extension must be .netmodule, otherwise .exe ",rangeCmdArgs));
|
|
System.IO.Path.GetFileNameWithoutExtension baseName
|
|
|
|
let pdbfile =
|
|
if tcConfigB.debuginfo then
|
|
Some (match tcConfigB.debugSymbolFile with None -> (Filename.chop_extension outfile)^"."^(Ilsupp.pdb_suffix_for_configuration (Ilsupp.current_configuration())) | Some f -> f)
|
|
elif (tcConfigB.debugSymbolFile <> None) && (not (tcConfigB.debuginfo)) then
|
|
error(Error("The --pdb option requires the --debug option to be used",rangeStartup))
|
|
else None
|
|
tcConfigB.outputFile <- Some(outfile)
|
|
outfile,pdbfile,assemblyName
|
|
member tcConfigB.TurnWarningOff(m,s:string) =
|
|
match GetWarningNumber(m,s) with
|
|
| None -> ()
|
|
| Some n ->
|
|
// nowarn 62 turns on mlCompatibility, e.g. shows ML compat items in intellisense menus
|
|
if n = 62 then tcConfigB.mlCompatibility <- true;
|
|
tcConfigB.specificWarnOff <- ListSet.insert (=) n tcConfigB.specificWarnOff
|
|
|
|
member tcConfigB.AddIncludePath (m,path) =
|
|
let absolutePath = ComputeMakePathAbsolute tcConfigB.implicitIncludeDir path
|
|
let ok =
|
|
let existsOpt =
|
|
try Some(Directory.Exists(absolutePath))
|
|
with e -> warning(Error("The search directory '"^path^"' is invalid",m)); None
|
|
match existsOpt with
|
|
| Some(exists) ->
|
|
if not exists then warning(Error("The search directory '"^absolutePath^"' could not be found",m));
|
|
exists
|
|
| None -> false
|
|
if ok && not (List.mem absolutePath tcConfigB.includes) then
|
|
tcConfigB.includes <- tcConfigB.includes ++ absolutePath
|
|
|
|
member tcConfigB.AddLoadedSource(m,path) =
|
|
if IsInvalidPath(path) then
|
|
warning(Error(Printf.sprintf "'%s' is not a valid filename" path,m))
|
|
else
|
|
let path = ComputeMakePathAbsolute tcConfigB.implicitIncludeDir path
|
|
|
|
if not (List.mem path (List.map snd tcConfigB.loadedSources)) then
|
|
tcConfigB.loadedSources <- tcConfigB.loadedSources ++ (m,path)
|
|
|
|
|
|
member tcConfigB.AddEmbeddedResource filename =
|
|
tcConfigB.embedResources <- tcConfigB.embedResources ++ filename
|
|
|
|
member tcConfigB.AddReferencedAssemblyByPath (m,path) =
|
|
if IsInvalidPath(path) then
|
|
warning(Error(Printf.sprintf "'%s' is not a valid assembly name" path,m))
|
|
elif not (List.mem (AssemblyReference(m,path)) tcConfigB.referencedDLLs) then // NOTE: We keep same paths if range is different.
|
|
tcConfigB.referencedDLLs <- tcConfigB.referencedDLLs ++ AssemblyReference(m,path)
|
|
|
|
|
|
static member SplitCommandLineResourceInfo ri =
|
|
if String.contains ri ',' then
|
|
let p = String.index ri ','
|
|
let file = String.sub ri 0 p
|
|
let rest = String.sub ri (p+1) (String.length ri - p - 1)
|
|
if String.contains rest ',' then
|
|
let p = String.index rest ','
|
|
let name = String.sub rest 0 p^".resources"
|
|
let pubpri = String.sub rest (p+1) (rest.Length - p - 1)
|
|
if pubpri = "public" then file,name,Resource_public
|
|
elif pubpri = "private" then file,name,Resource_private
|
|
else error(Error("unrecognized privacy setting "^pubpri^" for managed resource",rangeStartup))
|
|
else
|
|
file,rest^".resources",Resource_public
|
|
else
|
|
ri,System.IO.Path.GetFileName(ri),Resource_public
|
|
|
|
|
|
let OpenILBinary(filename,optimizeForMemory,openBinariesInMemory,ilGlobalsOpt,pdbPathOption,mscorlibAssemblyName) =
|
|
let ilGlobals =
|
|
match ilGlobalsOpt with
|
|
| None -> IL.mk_ILGlobals ScopeRef_local (Some mscorlibAssemblyName)
|
|
| Some ilGlobals -> ilGlobals
|
|
let opts = { Ilread.defaults with
|
|
Ilread.ilGlobals=ilGlobals;
|
|
// fsc.exe does not uses optimizeForMemory (hence keeps MORE caches in AbstractIL)
|
|
// fsi.exe does use optimizeForMemory (hence keeps FEWER caches in AbstractIL), because its long running
|
|
// Visual Studio does use optimizeForMemory (hence keeps FEWER caches in AbstractIL), because its long running
|
|
Ilread.optimizeForMemory=optimizeForMemory;
|
|
Ilread.pdbPath = pdbPathOption; }
|
|
|
|
// Visual Studio uses OpenILModuleReaderAfterReadingAllBytes for all DLLs to avoid having to dispose of any readers explicitly
|
|
if openBinariesInMemory // && not syslib
|
|
then Ilread.OpenILModuleReaderAfterReadingAllBytes filename opts
|
|
else Ilread.OpenILModuleReader filename opts
|
|
|
|
#if DEBUG
|
|
[<System.Diagnostics.DebuggerDisplayAttribute("AssemblyResolution({ResolvedPath})")>]
|
|
#endif
|
|
type AssemblyResolution =
|
|
{ originalReference : AssemblyReference
|
|
resolvedPath : string
|
|
resolvedFrom : ResolvedFrom
|
|
fusionName : string
|
|
fusionVersion : string
|
|
redist : string
|
|
sysdir : bool
|
|
}
|
|
member private this.ResolvedPath = this.resolvedPath
|
|
static member Default =
|
|
{originalReference = AssemblyReference(range0, null); resolvedPath = null; resolvedFrom = Unknown; fusionName = null; fusionVersion = null; redist = null; sysdir = false}
|
|
|
|
type UnresolvedReference = UnresolvedReference of string * AssemblyReference list
|
|
|
|
let highestInstalledFrameworkVersion = highestInstalledNetFrameworkVersionMajorMinor()
|
|
|
|
[<Sealed>]
|
|
/// This type is immutable and must be kept as such. Do not extract or mutate the underlying data except by cloning it.
|
|
type TcConfig(data : TcConfigBuilder,validate:bool) =
|
|
// Validate the inputs - this helps ensure errors in options are shown in visual studio rather than only when built
|
|
// However we only validate a minimal number of options at the moment
|
|
do if validate then try data.version.GetVersionInfo(data.implicitIncludeDir) |> ignore with e -> errorR(e)
|
|
|
|
// clone the input builder to ensure nobody messes with it.
|
|
let data = { data with pause = data.pause }
|
|
|
|
/// A closed set of assemblies where, for any subset S:
|
|
/// - the TcImports object built for S (and thus the F# Compiler CCUs for the assemblies in S)
|
|
/// is a resource that can be shared between any two IncrementalBuild objects that reference
|
|
/// precisely S
|
|
let systemAssemblies =
|
|
[data.mscorlibAssemblyName] @ [GetFSharpCoreLibraryName()] @ coreFramework @ extendedFramework @ ["System.Core"]
|
|
|
|
let computeKnownDllReference(referencedDLLs:AssemblyReference list, libraryName, pathOpt) =
|
|
let defaultCoreLibraryReference = AssemblyReference(rangeStartup,(match pathOpt with Some p -> Filename.concat p libraryName | None -> libraryName)^".dll")
|
|
match data.referencedDLLs |> List.filter(fun assemblyReference -> assemblyReference.SimpleAssemblyNameIs libraryName) with
|
|
| [AssemblyReference(m,f) as r] ->
|
|
let filename = ComputeMakePathAbsolute data.implicitIncludeDir f
|
|
if Internal.Utilities.FileSystem.File.SafeExists(filename) then
|
|
r,true
|
|
else
|
|
// If the file doesn't exist, let reference resolution logic report the error later...
|
|
defaultCoreLibraryReference, false
|
|
| [] ->
|
|
defaultCoreLibraryReference, false
|
|
| _ -> error(Error(sprintf "Multiple references to %s.dll are not permitted" libraryName,rangeCmdArgs))
|
|
|
|
// Look for an explicit reference to mscorlib and use that to compute clrRoot and targetFrameworkVersion
|
|
let mscorlibReference,isMscorlibExplicit = computeKnownDllReference(data.referencedDLLs,data.mscorlibAssemblyName,None)
|
|
let fslibReference,isFslibExplicit = computeKnownDllReference(data.referencedDLLs,GetFSharpCoreLibraryName(),Some(data.defaultFSharpBinariesDir))
|
|
|
|
let clrRootValue,(mscorlibMajorVersion,targetFrameworkVersionValue) =
|
|
if isMscorlibExplicit then
|
|
let filename = ComputeMakePathAbsolute data.implicitIncludeDir mscorlibReference.Text
|
|
try
|
|
|
|
let ilReader = OpenILBinary(filename,data.optimizeForMemory,data.openBinariesInMemory,None,None,data.mscorlibAssemblyName)
|
|
try
|
|
let ilModule = ilReader.ILModuleDef
|
|
match ilModule.ManifestOfAssembly.Version with
|
|
| Some(v1,v2,_,_) ->
|
|
if v1 = 1us then
|
|
warning(Error(sprintf "The file '%s' is a CLI 1.x version of mscorlib. F# requires CLI version 2.0 or greater" filename,rangeStartup))
|
|
let clrRoot = Some(Path.GetDirectoryName(Path.GetFullPath(filename)))
|
|
clrRoot, (int v1, sprintf "v%d.%d" v1 v2)
|
|
| _ ->
|
|
failwith "could not read version from mscorlib.dll"
|
|
finally
|
|
Ilread.CloseILModuleReader ilReader
|
|
with _ ->
|
|
error(Error(sprintf "Unable to read assembly '%s'" filename,rangeStartup))
|
|
else
|
|
None, highestInstalledFrameworkVersion
|
|
|
|
// Check that the referenced version of FSharp.COre.dll matches the referenced version of mscorlib.dll
|
|
let checkFSharpBinaryCompatWithMscorlib filename (ilAssemblyRefs: ILAssemblyRef list) m =
|
|
match ilAssemblyRefs |> List.tryFind (fun aref -> aref.Name = data.mscorlibAssemblyName) with
|
|
| Some aref when
|
|
(match aref.Version with
|
|
| Some(v1,_,_,_) -> ((v1 < 4us) <> (mscorlibMajorVersion < 4))
|
|
| _ -> false) ->
|
|
warning(Error(sprintf "The referenced or default base CLI library 'mscorlib' is binary-incompatible with the referenced F# core library '%s'. Consider recompiling the library or making an explicit reference to a version of this library that matches the CLI version you are using" filename,m))
|
|
| _ ->
|
|
()
|
|
|
|
// Look for an explicit reference to FSharp.Core and use that to compute fsharpBinariesDir
|
|
let fsharpBinariesDirValue =
|
|
if isFslibExplicit then
|
|
let filename = ComputeMakePathAbsolute data.implicitIncludeDir fslibReference.Text
|
|
try
|
|
let ilReader = OpenILBinary(filename,data.optimizeForMemory,data.openBinariesInMemory,None,None,data.mscorlibAssemblyName)
|
|
try
|
|
checkFSharpBinaryCompatWithMscorlib filename ilReader.ILAssemblyRefs rangeStartup;
|
|
let fslibRoot = Path.GetDirectoryName(Path.GetFullPath(filename))
|
|
fslibRoot (* , sprintf "v%d.%d" v1 v2 *)
|
|
finally
|
|
Ilread.CloseILModuleReader ilReader
|
|
with _ ->
|
|
error(Error(sprintf "Unable to read assembly '%s'" filename,rangeStartup))
|
|
else
|
|
data.defaultFSharpBinariesDir
|
|
|
|
|
|
|
|
member x.mscorlibAssemblyName = data.mscorlibAssemblyName
|
|
member x.autoResolveOpenDirectivesToDlls = data.autoResolveOpenDirectivesToDlls
|
|
member x.noFeedback = data.noFeedback
|
|
member x.implicitIncludeDir = data.implicitIncludeDir
|
|
member x.openBinariesInMemory = data.openBinariesInMemory
|
|
member x.openDebugInformationForLaterStaticLinking = data.openDebugInformationForLaterStaticLinking
|
|
member x.fsharpBinariesDir = fsharpBinariesDirValue
|
|
member x.compilingFslib = data.compilingFslib
|
|
member x.useIncrementalBuilder = data.useIncrementalBuilder
|
|
member x.includes = data.includes
|
|
member x.implicitOpens = data.implicitOpens
|
|
member x.useFsiAuxLib = data.useFsiAuxLib
|
|
member x.framework = data.framework
|
|
member x.implicitlyResolveAssemblies = data.implicitlyResolveAssemblies
|
|
member x.resolutionEnvironment = data.resolutionEnvironment
|
|
member x.light = data.light
|
|
member x.conditionalCompilationDefines = data.conditionalCompilationDefines
|
|
member x.loadedSources = data.loadedSources
|
|
member x.referencedDLLs = data.referencedDLLs
|
|
member x.clrRoot = clrRootValue
|
|
member x.optimizeForMemory = data.optimizeForMemory
|
|
member x.inputCodePage = data.inputCodePage
|
|
member x.embedResources = data.embedResources
|
|
member x.globalWarnAsError = data.globalWarnAsError
|
|
member x.globalWarnLevel = data.globalWarnLevel
|
|
member x.specificWarnOff = data. specificWarnOff
|
|
member x.specificWarnAsError = data.specificWarnAsError
|
|
member x.mlCompatibility = data.mlCompatibility
|
|
member x.checkOverflow = data.checkOverflow
|
|
member x.showReferenceResolutions = data.showReferenceResolutions
|
|
member x.outputFile = data.outputFile
|
|
member x.resolutionFrameworkRegistryBase = data.resolutionFrameworkRegistryBase
|
|
member x.resolutionAssemblyFoldersSuffix = data. resolutionAssemblyFoldersSuffix
|
|
member x.resolutionAssemblyFoldersConditions = data. resolutionAssemblyFoldersConditions
|
|
member x.platform = data.platform
|
|
member x.useMonoResolution = data.useMonoResolution
|
|
member x.target = data.target
|
|
member x.debuginfo = data.debuginfo
|
|
member x.debugSymbolFile = data.debugSymbolFile
|
|
member x.typeCheckOnly = data.typeCheckOnly
|
|
member x.parseOnly = data.parseOnly
|
|
member x.simulateException = data.simulateException
|
|
member x.printAst = data.printAst
|
|
member x.targetFrameworkVersionMajorMinor = targetFrameworkVersionValue
|
|
member x.tokenizeOnly = data.tokenizeOnly
|
|
member x.testInteractionParser = data.testInteractionParser
|
|
member x.reportNumDecls = data.reportNumDecls
|
|
member x.printSignature = data.printSignature
|
|
member x.printSignatureFile = data.printSignatureFile
|
|
member x.xmlDocOutputFile = data.xmlDocOutputFile
|
|
member x.generateHtmlDocs = data.generateHtmlDocs
|
|
member x.htmlDocDirectory = match data.htmlDocDirectory with | None -> None | Some(x) -> Some(if System.IO.Path.IsPathRooted(x) then x else System.IO.Path.Combine(data.implicitIncludeDir, x))
|
|
member x.htmlDocCssFile = data.htmlDocCssFile
|
|
member x.htmlDocNamespaceFile = data.htmlDocNamespaceFile
|
|
member x.htmlDocAppendFlag = data.htmlDocAppendFlag
|
|
member x.htmlDocLocalLinks = data.htmlDocLocalLinks
|
|
member x.stats = data.stats
|
|
member x.generateFilterBlocks = data.generateFilterBlocks
|
|
member x.signer = data.signer
|
|
member x.container = data.container
|
|
member x.delaysign = data.delaysign
|
|
member x.version = data.version
|
|
member x.standalone = data.standalone
|
|
member x.extraStaticLinkRoots = data.extraStaticLinkRoots
|
|
member x.noSignatureData = data.noSignatureData
|
|
member x.onlyEssentialOptimizationData = data.onlyEssentialOptimizationData
|
|
member x.useOptimizationDataFile = data.useOptimizationDataFile
|
|
member x.jitTracking = data.jitTracking
|
|
member x.ignoreSymbolStoreSequencePoints = data.ignoreSymbolStoreSequencePoints
|
|
member x.internConstantStrings = data.internConstantStrings
|
|
member x.generateConfigFile = data.generateConfigFile
|
|
member x.extraOptimizationIterations = data.extraOptimizationIterations
|
|
member x.win32res = data.win32res
|
|
member x.win32manifest = data.win32manifest
|
|
member x.includewin32manifest = data.includewin32manifest
|
|
member x.linkResources = data.linkResources
|
|
member x.showFullPaths = data.showFullPaths
|
|
member x.errorStyle = data.errorStyle
|
|
member x.utf8output = data.utf8output
|
|
member x.flatErrors = data.flatErrors
|
|
member x.maxErrors = data.maxErrors
|
|
member x.baseAddress = data.baseAddress
|
|
#if DEBUG
|
|
member x.writeGeneratedILFiles = data.writeGeneratedILFiles
|
|
member x.showOptimizationData = data.showOptimizationData
|
|
#endif
|
|
member x.showTerms = data.showTerms
|
|
member x.writeTermsToFiles = data.writeTermsToFiles
|
|
member x.doDetuple = data.doDetuple
|
|
member x.doTLR = data.doTLR
|
|
member x.optSettings = data.optSettings
|
|
member x.optsOn = data.optsOn
|
|
member x.product = data.product
|
|
member x.showBanner = data.showBanner
|
|
member x.showTimes = data.showTimes
|
|
member x.pause = data.pause
|
|
|
|
static member Create(builder,validate) = TcConfig(builder,validate)
|
|
|
|
member tcConfig.CloneOfOriginalBuilder =
|
|
{ data with conditionalCompilationDefines=data.conditionalCompilationDefines }
|
|
|
|
member tcConfig.ComputeCanContainEntryPoint(sourceFiles:string list) =
|
|
let n = sourceFiles.Length in
|
|
sourceFiles |> List.mapi (fun i nm -> (i=n-1) && tcConfig.target.IsExe)
|
|
|
|
// This call can fail if no CLR is found (this is the path to mscorlib)
|
|
member tcConfig.ClrRoot =
|
|
match tcConfig.clrRoot with
|
|
| Some x ->
|
|
[tcConfig.MakePathAbsolute x]
|
|
| None ->
|
|
// When running on Mono we lead everyone to believe we're doing .NET 2.0 compilation
|
|
// by default.
|
|
if runningOnMono then
|
|
let mono10SysDir = System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()
|
|
assert(mono10SysDir.EndsWith("1.0",StringComparison.Ordinal));
|
|
let mono20SysDir = Path.Combine(Path.GetDirectoryName mono10SysDir, "2.0")
|
|
let mono21SysDir = Path.Combine(Path.GetDirectoryName mono10SysDir, "2.1")
|
|
if Directory.Exists(mono20SysDir) then
|
|
if Directory.Exists(mono21SysDir) then
|
|
[mono21SysDir;mono20SysDir]
|
|
else
|
|
[mono20SysDir]
|
|
else [mono10SysDir]
|
|
else
|
|
try [System.Runtime.InteropServices.RuntimeEnvironment.GetRuntimeDirectory()]
|
|
with e -> errorRecovery e range0; []
|
|
|
|
member tcConfig.ComputeLightSyntaxInitialStatus filename =
|
|
let lower = String.lowercase filename
|
|
let lightOnByDefault = List.exists (Filename.check_suffix lower) lightSyntaxDefaultExtensions
|
|
if lightOnByDefault then (tcConfig.light <> Some(false)) else (tcConfig.light = Some(true) )
|
|
|
|
member tcConfig.ComputeSyntaxFlagRequired filename =
|
|
let lower = String.lowercase filename
|
|
List.exists (Filename.check_suffix lower) syntaxFlagRequiredExtensions
|
|
|
|
member tcConfig.GetAvailableLoadedSources() =
|
|
let ResolveLoadedSource (m,path) =
|
|
try
|
|
let path = tcConfig.MakePathAbsolute path
|
|
if not(Internal.Utilities.FileSystem.File.SafeExists(path)) then
|
|
error(LoadedSourceNotFoundIgnoring(path,m))
|
|
None
|
|
else Some(m,path)
|
|
with e -> errorRecovery e m; None
|
|
|
|
tcConfig.loadedSources |> List.map ResolveLoadedSource |> List.filter Option.is_some |> List.map Option.get
|
|
|
|
|
|
/// Return true if this is an installed system memory that is allowed to be locked or placed into the
|
|
/// 'framework' reference set that is potentially shared across multiple compilations.
|
|
member tcConfig.IsSystemAssembly (filename:string) =
|
|
try
|
|
Internal.Utilities.FileSystem.File.SafeExists(filename) &&
|
|
(let baseFilename = Path.GetFileNameWithoutExtension(filename)
|
|
systemAssemblies |> List.exists(fun s->s=baseFilename))
|
|
with e ->
|
|
false
|
|
|
|
|
|
// This is not the complete set of search paths, it is just the set that is special to F# (as compared to MSBuild resolution)
|
|
member tcConfig.SearchPathsForLibraryFiles =
|
|
(tcConfig.ClrRoot @
|
|
List.map (tcConfig.MakePathAbsolute) tcConfig.includes ++
|
|
tcConfig.implicitIncludeDir ++
|
|
tcConfig.fsharpBinariesDir)
|
|
|
|
member tcConfig.SearchPathsForSourceFiles =
|
|
List.map (tcConfig.MakePathAbsolute) tcConfig.includes ++
|
|
tcConfig.implicitIncludeDir
|
|
|
|
member tcConfig.MakePathAbsolute path =
|
|
let result = ComputeMakePathAbsolute tcConfig.implicitIncludeDir path
|
|
#if TRACK_DOWN_EXTRA_BACKSLASHES
|
|
System.Diagnostics.Debug.Assert(not(result.Contains(@"\\")), "tcConfig.MakePathAbsolute results in a non-canonical filename with extra backslashes: "^result)
|
|
#endif
|
|
result
|
|
|
|
member tcConfig.ResolveLibWithDirectories (AssemblyReference (m,nm) as r) =
|
|
let resolved = TryResolveFileUsingPaths(tcConfig.SearchPathsForLibraryFiles,m,nm)
|
|
let sysdir = tcConfig.IsSystemAssembly resolved
|
|
{AssemblyResolution.Default with originalReference=r;resolvedPath=resolved;resolvedFrom=Unknown;sysdir=sysdir}
|
|
|
|
member tcConfig.ResolveSourceFile (m,nm) =
|
|
TryResolveFileUsingPaths(tcConfig.SearchPathsForSourceFiles,m,nm)
|
|
|
|
member tcConfig.CheckFSharpBinary (filename,ilAssemblyRefs,m) =
|
|
checkFSharpBinaryCompatWithMscorlib filename ilAssemblyRefs m
|
|
|
|
// NOTE!! if mode=Speculative then this method must not report ANY warnings or errors through 'warning' or 'error'. Instead
|
|
// it must return warnings and errors as data
|
|
//
|
|
// NOTE!! if mode=ReportErrors then this method must not raise exceptions. It must just report the errors and recover
|
|
static member TryResolveLibsUsingMSBuildRules (tcConfig:TcConfig,originalReferences:AssemblyReference list, errorAndWarningRange:range, mode:ResolveLibFileMode) : AssemblyResolution list * UnresolvedReference list =
|
|
use t = Trace.Call("Build","TryResolveLibsUsingMSBuildRules", fun _->sprintf "Original references %A" originalReferences)
|
|
|
|
if tcConfig.useMonoResolution then
|
|
failwith "MSBuild resolution is not supported."
|
|
|
|
if originalReferences=[] then [],[]
|
|
else
|
|
// Group references by name with range values in the grouped value list.
|
|
let groupedReferences =
|
|
originalReferences
|
|
|> Seq.group_by(fun r -> r.Text)
|
|
|> Seq.map(fun (name,s)->name,s |> List.of_seq)
|
|
|> Array.of_seq
|
|
|
|
// Check whether the given file is a .NET assembly.
|
|
// Related to Dev10 515444. GetAssemblyName called by MSBuild's ResolveAssemblyReference
|
|
// will throw a ExecutionEngineException if things like notepad.exe. Attempt to prefilter
|
|
// non->NET assemblies by cracking the PE header and looking at the section (RVA) that points
|
|
// to managed code.
|
|
let IsNetAssembly file =
|
|
try
|
|
use fs = new FileStream(file, FileMode.Open, FileAccess.Read)
|
|
use reader = new BinaryReader(fs)
|
|
fs.Position <- 060L // Jump to PE Header
|
|
let header = reader.ReadUInt32() // Read the header position
|
|
fs.Position <- int64 header
|
|
let magic = reader.ReadUInt16() // the magic number lets us know if we're dealing with a 32 or 64-bit header
|
|
fs.Position <- int64 (header + (if magic = 0x020Bus then 248u else 232u)) // Jump to RVA
|
|
let rva14 = reader.ReadUInt32()
|
|
(rva14<>0u)
|
|
with
|
|
| :? System.UnauthorizedAccessException -> false
|
|
| :? System.IO.EndOfStreamException -> false
|
|
| :? System.ArgumentOutOfRangeException -> false
|
|
| :? System.IO.IOException -> false
|
|
|
|
let IsNotFileOrIsAssembly file =
|
|
let file = if Path.IsPathRooted(file) then file else Path.Combine(tcConfig.implicitIncludeDir, file)
|
|
not(Internal.Utilities.FileSystem.File.SafeExists(file)) || IsNetAssembly(file)
|
|
|
|
let logmessage showMessages =
|
|
if showMessages && tcConfig.showReferenceResolutions then (fun (message:string)->dprintf "%s\n" message)
|
|
else (fun message->())
|
|
let logwarning showMessages =
|
|
(fun code message->
|
|
if showMessages && mode = ReportErrors then
|
|
match code with
|
|
| "MSB3106" ->
|
|
// These are warnings that mean 'not resolved' for some assembly.
|
|
// Note that we don't get to know the name of the assembly that couldn't be resolved.
|
|
// Ignore these and rely on the logic below to emit an error for each unresolved reference.
|
|
()
|
|
| _ ->
|
|
(if code = "MSB3245" then errorR else warning)
|
|
(MSBuildReferenceResolutionWarning(code,message,errorAndWarningRange)))
|
|
let logerror showMessages =
|
|
(fun code message ->
|
|
if showMessages && mode = ReportErrors then
|
|
errorR(MSBuildReferenceResolutionError(code,message,errorAndWarningRange)))
|
|
|
|
let targetFrameworkMajorMinor = tcConfig.targetFrameworkVersionMajorMinor
|
|
|
|
#if DEBUG
|
|
assert( Set.contains targetFrameworkMajorMinor (set ["v2.0";"v3.0";"v3.5";"v4.0"]) ) // Resolve is flexible, but pinning down targetFrameworkMajorMinor.
|
|
#endif
|
|
|
|
let targetProcessorArchitecture =
|
|
match tcConfig.platform with
|
|
| None -> "" // msil
|
|
| Some(X86) -> "x86"
|
|
| Some(AMD64) -> "amd64"
|
|
| Some(IA64) -> "ia64"
|
|
let outputDirectory =
|
|
match tcConfig.outputFile with
|
|
| Some(outputFile) -> tcConfig.MakePathAbsolute outputFile
|
|
| None -> tcConfig.implicitIncludeDir
|
|
let targetFrameworkDirectories =
|
|
match tcConfig.clrRoot with
|
|
| Some(clrRoot) -> [tcConfig.MakePathAbsolute clrRoot]
|
|
| None -> []
|
|
|
|
let references = [|0..groupedReferences.Length-1|]
|
|
|> Array.map(fun i->(fst groupedReferences.[i]),(string)i)
|
|
|> Array.filter(fst >> IsNotFileOrIsAssembly)
|
|
|
|
let Resolve(references,showMessages) =
|
|
try
|
|
MSBuildResolver.Resolve
|
|
(tcConfig.resolutionEnvironment,
|
|
references,
|
|
targetFrameworkMajorMinor, // TargetFrameworkVersionMajorMinor
|
|
targetFrameworkDirectories, // TargetFrameworkDirectories
|
|
targetProcessorArchitecture, // TargetProcessorArchitecture
|
|
Path.GetDirectoryName(outputDirectory), // Output directory
|
|
tcConfig.fsharpBinariesDir, // FSharp binaries directory
|
|
tcConfig.includes, // Explicit include directories
|
|
tcConfig.implicitIncludeDir, // Implicit include directory (likely the project directory)
|
|
tcConfig.resolutionFrameworkRegistryBase,
|
|
tcConfig.resolutionAssemblyFoldersSuffix,
|
|
tcConfig.resolutionAssemblyFoldersConditions,
|
|
logmessage showMessages, logwarning showMessages, logerror showMessages)
|
|
with
|
|
MSBuildResolver.ResolutionFailure -> error(Error("Assembly resolution failure at or near this location",errorAndWarningRange))
|
|
|
|
let resolutions = Resolve(references,(*showMessages*)true)
|
|
|
|
let resultingResolutions =
|
|
resolutions.resolvedFiles
|
|
|> Array.map(fun resolvedFile ->
|
|
let i = (int)(resolvedFile.baggage)
|
|
let original,ms = groupedReferences.[i]
|
|
ms|>List.map(fun originalReference->
|
|
System.Diagnostics.Debug.Assert(System.IO.Path.IsPathRooted(resolvedFile.itemSpec), sprintf "msbuild-resolved path is not absolute: '%s'" resolvedFile.itemSpec)
|
|
let canonicalItemSpec = System.IO.Path.GetFullPath(resolvedFile.itemSpec)
|
|
{originalReference=originalReference;
|
|
resolvedPath=canonicalItemSpec;
|
|
resolvedFrom=resolvedFile.resolvedFrom;
|
|
fusionName=resolvedFile.fusionName;
|
|
fusionVersion=resolvedFile.version;
|
|
redist=resolvedFile.redist;
|
|
sysdir=tcConfig.IsSystemAssembly canonicalItemSpec}))
|
|
|> List.of_array
|
|
|> List.flatten
|
|
|
|
// O(N^2) here over a small set of referenced assemblies.
|
|
let IsResolved(originalName:string) =
|
|
if resultingResolutions |> List.exists(fun resolution -> resolution.originalReference.Text = originalName) then true
|
|
else
|
|
// MSBuild resolution may have unified the result of two duplicate references. Try to re-resolve now.
|
|
// If re-resolution worked then this was a removed duplicate.
|
|
Resolve([|originalName,""|],(*showMessages*)false).resolvedFiles.Length<>0
|
|
|
|
let unresolvedReferences =
|
|
groupedReferences
|
|
//|> Array.filter(fst >> IsNotFileOrIsAssembly)
|
|
|> Array.filter(fst >> IsResolved >> not)
|
|
|> List.of_array
|
|
|
|
// Report that an assembly was not resolved.
|
|
let ReportAssemblyNotResolved(file,originalReferences:AssemblyReference list) =
|
|
Trace.PrintLine("Build", fun () -> sprintf "Reporting error about assembly not found: %s" file)
|
|
originalReferences |> List.iter(fun originalReference -> errorR(AssemblyNotResolved(file,originalReference.Range)))
|
|
|
|
// Search for original references that are not in the resolved set and issue errors for them
|
|
if mode = ReportErrors then
|
|
unresolvedReferences |> List.iter(ReportAssemblyNotResolved)
|
|
|
|
// If mode=Speculative, then we haven't reported any errors.
|
|
// We report the error condition by returning an empty list of resolutions
|
|
if mode = Speculative && (originalReferences |> List.exists(fun r -> not (IsResolved r.Text))) then
|
|
[],(List.of_array groupedReferences) |> List.map UnresolvedReference
|
|
else
|
|
resultingResolutions,unresolvedReferences |> List.map UnresolvedReference
|
|
|
|
|
|
member tcConfig.MscorlibDllReference() = mscorlibReference
|
|
|
|
member tcConfig.CoreLibraryDllReference() = fslibReference
|
|
|
|
|
|
let warningMem n l = n <> 0 && List.mem n l
|
|
|
|
let ReportWarning (globalWarnLevel : int) (specificWarnOff : int list) (err:exn) =
|
|
let n = GetErrorNumber err
|
|
warningOn err globalWarnLevel && not (warningMem n specificWarnOff)
|
|
|
|
let ReportWarningAsError (globalWarnLevel : int) (specificWarnOff : int list) (specificWarnAsError : int list) (globalWarnAsError : bool) (err:exn) =
|
|
(warningOn err globalWarnLevel) &&
|
|
((globalWarnAsError && not (warningMem (GetErrorNumber err) specificWarnOff)) ||
|
|
warningMem (GetErrorNumber err) specificWarnAsError)
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Scoped #nowarn pragmas
|
|
|
|
|
|
let GetScopedPragmasForHashDirective hd =
|
|
[ match hd with
|
|
| HashDirective("nowarn",[s],m) ->
|
|
match GetWarningNumber(m,s) with
|
|
| None -> ()
|
|
| Some n -> yield WarningOff(m,n)
|
|
| _ -> () ]
|
|
|
|
let GetScopedPragmasForInput input =
|
|
|
|
match input with
|
|
| SigFileInput (SigFile(_,_,pragmas,_,_)) -> pragmas
|
|
| ImplFileInput (ImplFile(_,_,_,pragmas,_,_,_)) ->pragmas
|
|
|
|
|
|
|
|
/// Build an ErrorLogger that delegates to another ErrorLogger but filters warnings turned off by the given pragma declarations
|
|
//
|
|
// NOTE: we allow a flag to turn of strict file checking. This is because file names sometimes don't match due to use of
|
|
// #line directives, e.g. for pars.fs/pars.fsy. In this case we just test by line number - in most cases this is sufficent
|
|
// because we install a filtering error handler on a file-by-file basis for parsing and type-checking.
|
|
// However this is indicative of a more systematic problem where source-line
|
|
// sensitive operations (lexfilter and warning filtering) do not always
|
|
// interact well with #line directives.
|
|
type ErrorLoggerFilteringByScopedPragmas (checkFile,scopedPragmas,errorLogger:ErrorLogger) =
|
|
let mutable scopedPragmas = scopedPragmas
|
|
member x.ScopedPragmas with set(v) = scopedPragmas <- v
|
|
interface ErrorLogger with
|
|
member x.ErrorSink(e) = errorLogger.ErrorSink(e)
|
|
member x.ErrorCount = errorLogger.ErrorCount
|
|
member x.WarnSink(err:exn) =
|
|
let report =
|
|
let warningNum = GetErrorNumber err
|
|
match RangeOfError err with
|
|
| Some m -> not (scopedPragmas |> List.exists (fun pragma ->
|
|
match pragma with
|
|
| WarningOff(pragmaRange,warningNumFromPragma) ->
|
|
warningNum = warningNumFromPragma &&
|
|
(not checkFile || Range.file_idx_of_range m = Range.file_idx_of_range pragmaRange) &&
|
|
Range.pos_geq (Range.start_of_range m) (Range.start_of_range pragmaRange)))
|
|
| None -> true
|
|
if report then errorLogger.WarnSink err;
|
|
|
|
let GetErrorLoggerFilteringByScopedPragmas(checkFile,scopedPragmas,errorLogger) =
|
|
(ErrorLoggerFilteringByScopedPragmas(checkFile,scopedPragmas,errorLogger) :> ErrorLogger)
|
|
|
|
/// Build an ErrorLogger that delegates to another ErrorLogger but filters warnings turned off by the given pragma declarations
|
|
type DelayedErrorLogger(errorLogger:ErrorLogger) =
|
|
let delayed = new ResizeArray<_>()
|
|
interface ErrorLogger with
|
|
member x.ErrorSink(e) = delayed.Add (e,true)
|
|
member x.ErrorCount = delayed |> Seq.filter snd |> Seq.length
|
|
member x.WarnSink(e) = delayed.Add(e,false)
|
|
member x.CommitDelayedErrorsAndWarnings() =
|
|
// Eagerly grab all the errors and warnings from the mutable collection
|
|
let errors = delayed |> Seq.to_list
|
|
// Now report them
|
|
for (e,isError) in errors do
|
|
if isError then errorLogger.ErrorSink(e) else errorLogger.WarnSink(e)
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Parsing
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
let CanonicalizeFilename filename =
|
|
let basic = Path.GetFileName filename
|
|
String.capitalize (try Filename.chop_extension basic with _ -> basic)
|
|
|
|
let QualFileNameOfModuleName m modname = QualifiedNameOfFile(mksyn_id m (text_of_lid modname))
|
|
let QualFileNameOfFilename m filename = QualifiedNameOfFile(mksyn_id m (CanonicalizeFilename filename))
|
|
let QualFileNameOfUniquePath (m, p: string list) = QualifiedNameOfFile(mksyn_id m (String.concat "_" p))
|
|
|
|
let QualFileNameOfSpecs filename specs =
|
|
match specs with
|
|
| [ModuleOrNamespaceSpec(modname,true,_,_,_,_,m)] -> QualFileNameOfModuleName m modname
|
|
| _ -> QualFileNameOfFilename (rangeN filename 1) filename
|
|
|
|
let QualFileNameOfImpls filename specs =
|
|
match specs with
|
|
| [ModuleOrNamespaceImpl(modname,true,_,_,_,_,m)] -> QualFileNameOfModuleName m modname
|
|
| _ -> QualFileNameOfFilename (rangeN filename 1) filename
|
|
|
|
let PrepandPathToQualFileName x (QualifiedNameOfFile(q)) = QualFileNameOfUniquePath (q.idRange,path_of_lid x@[q.idText])
|
|
let PrepandPathToImpl x (ModuleOrNamespaceImpl(p,c,d,e,f,g,h)) = ModuleOrNamespaceImpl(x@p,c,d,e,f,g,h)
|
|
let PrepandPathToSpec x (ModuleOrNamespaceSpec(p,c,d,e,f,g,h)) = ModuleOrNamespaceSpec(x@p,c,d,e,f,g,h)
|
|
|
|
let PrependPathToInput x inp =
|
|
match inp with
|
|
| ImplFileInput (ImplFile(b,c,q,d,hd,impls,e)) -> ImplFileInput (ImplFile(b,c,PrepandPathToQualFileName x q,d,hd,List.map (PrepandPathToImpl x) impls,e))
|
|
| SigFileInput (SigFile(b,q,d,hd,specs)) -> SigFileInput(SigFile(b,PrepandPathToQualFileName x q,d,hd,List.map (PrepandPathToSpec x) specs))
|
|
|
|
let ComputeAnonModuleName check defaultNamespace filename m =
|
|
let modname = CanonicalizeFilename filename
|
|
if check && not (modname |> String.for_all (fun c -> System.Char.IsLetterOrDigit(c) || c = '_')) then
|
|
if not (filename.EndsWith("fsx",StringComparison.OrdinalIgnoreCase) || filename.EndsWith("fsscript",StringComparison.OrdinalIgnoreCase)) then // bug://2893
|
|
warning(Error(sprintf "The declarations in this file will be placed in an implicit module '%s' based on the file name '%s'. However this is not a valid F# identifier, so the contents will not be accessible from other files. Consider renaming the file or adding a 'module' or 'namespace' declaration at the top of the file" modname (Path.GetFileName filename),m));
|
|
let combined =
|
|
match defaultNamespace with
|
|
| None -> modname
|
|
| Some ns -> text_of_path [ns;modname]
|
|
path_to_lid m (split_namespace combined)
|
|
|
|
let PostParseModuleImpl i defaultNamespace filename impl =
|
|
match impl with
|
|
| NamedTopModuleImpl(ModuleOrNamespaceImpl(lid,isModule,decls,xmlDoc,attribs,access,m)) ->
|
|
ModuleOrNamespaceImpl(lid,isModule,decls,xmlDoc,attribs,access,m)
|
|
| AnonTopModuleImpl (defs,m)->
|
|
let modname = ComputeAnonModuleName (nonNil defs) defaultNamespace filename m
|
|
ModuleOrNamespaceImpl(modname,true,defs,emptyPreXmlDoc,[],None,m)
|
|
| AnonNamespaceFragmentImpl (nsname,b,c,d,e,m)->
|
|
ModuleOrNamespaceImpl(nsname,b,c,d,e,None,m)
|
|
|
|
let PostParseModuleSpec i defaultNamespace filename intf =
|
|
match intf with
|
|
| NamedTopModuleSpec(x) -> x
|
|
| AnonTopModuleSpec (defs,m) ->
|
|
let modname = ComputeAnonModuleName (nonNil defs) defaultNamespace filename m
|
|
ModuleOrNamespaceSpec(modname,true,defs,emptyPreXmlDoc,[],None,m)
|
|
| AnonNamespaceFragmentSpec (nsname,b,c,d,e,m)->
|
|
ModuleOrNamespaceSpec(nsname,b,c,d,e,None,m)
|
|
|
|
|
|
|
|
let IsScript filename =
|
|
let lower = String.lowercase filename
|
|
scriptSuffixes |> List.exists (Filename.check_suffix lower)
|
|
|
|
|
|
let PostParseModuleImpls (defaultNamespace,filename,canContainEntryPoint,ParsedImplFile(hashDirectives,impls)) =
|
|
let impls = impls |> List.mapi (fun i x -> PostParseModuleImpl i defaultNamespace filename x)
|
|
let qualName = QualFileNameOfImpls filename impls
|
|
let isScript = IsScript filename
|
|
|
|
let scopedPragmas =
|
|
[ for (ModuleOrNamespaceImpl(_,_,decls,_,_,_,_)) in impls do
|
|
for d in decls do
|
|
match d with
|
|
| Def_hash (hd,_) -> yield! GetScopedPragmasForHashDirective hd
|
|
| _ -> ()
|
|
for hd in hashDirectives do
|
|
yield! GetScopedPragmasForHashDirective hd ]
|
|
ImplFileInput(ImplFile(filename,isScript,qualName,scopedPragmas,hashDirectives,impls,canContainEntryPoint))
|
|
|
|
let PostParseModuleSpecs (defaultNamespace,filename,ParsedSigFile(hashDirectives,specs)) =
|
|
let specs = specs |> List.mapi (fun i x -> PostParseModuleSpec i defaultNamespace filename x)
|
|
let qualName = QualFileNameOfSpecs filename specs
|
|
let scopedPragmas =
|
|
[ for (ModuleOrNamespaceSpec(_,_,decls,_,_,_,_)) in specs do
|
|
for d in decls do
|
|
match d with
|
|
| Spec_hash(hd,_) -> yield! GetScopedPragmasForHashDirective hd
|
|
| _ -> ()
|
|
for hd in hashDirectives do
|
|
yield! GetScopedPragmasForHashDirective hd ]
|
|
|
|
SigFileInput(SigFile(filename,qualName,scopedPragmas,hashDirectives,specs))
|
|
|
|
let ParseInput (lexer,errorLogger:ErrorLogger,lexbuf:UnicodeLexing.Lexbuf,defaultNamespace,filename,canContainEntryPoint) =
|
|
// The assert below is almost ok, but it fires in two cases:
|
|
// - fsi.exe sometimes passes "stdin" as a dummy filename
|
|
// - if you have a #line directive, e.g.
|
|
// # 1000 "Line01.fs"
|
|
// then it also asserts. But these are edge cases that can be fixed later, e.g. in bug 4651.
|
|
//System.Diagnostics.Debug.Assert(System.IO.Path.IsPathRooted(filename), sprintf "should be absolute: '%s'" filename)
|
|
let lower = String.lowercase filename
|
|
// Delay sending errors and warnings until after the file is parsed. This gives us a chance to scrape the
|
|
// #nowarn declarations for the file
|
|
let filteringErrorLogger = ErrorLoggerFilteringByScopedPragmas(false,[],errorLogger)
|
|
let errorLogger = DelayedErrorLogger(filteringErrorLogger)
|
|
use unwind = InstallGlobalErrorLogger (fun _ -> errorLogger)
|
|
try
|
|
let input =
|
|
if implSuffixes |> List.exists (Filename.check_suffix lower) then
|
|
let impl = Parser.implementationFile lexer lexbuf
|
|
PostParseModuleImpls (defaultNamespace,filename,canContainEntryPoint,impl)
|
|
elif sigSuffixes |> List.exists (Filename.check_suffix lower) then
|
|
let intfs = Parser.signatureFile lexer lexbuf
|
|
PostParseModuleSpecs (defaultNamespace,filename,intfs)
|
|
else
|
|
errorLogger.Error(InternalError("ParseInput: unknown file suffix",Range.rangeStartup))
|
|
filteringErrorLogger.ScopedPragmas <- GetScopedPragmasForInput input
|
|
input
|
|
finally
|
|
// OK, now commit the errors, since the ScopedPragmas will (hopefully) have been scraped
|
|
errorLogger.CommitDelayedErrorsAndWarnings()
|
|
|
|
|
|
|
|
|
|
[<Sealed>]
|
|
type TcAssemblyResolutions(results : AssemblyResolution list, unresolved : UnresolvedReference list) =
|
|
|
|
let originalReferenceToResolution = results |> List.map (fun r -> r.originalReference.Text,r) |> Map.of_list
|
|
let resolvedPathToResolution = results |> List.map (fun r -> r.resolvedPath,r) |> Map.of_list
|
|
|
|
/// Add some resolutions to the map of resolution results.
|
|
member tcResolutions.AddResolutionResults(newResults) = TcAssemblyResolutions(newResults @ results, unresolved)
|
|
/// Add some unresolved results.
|
|
member tcResolutions.AddUnresolvedReferences(newUnresolved) = TcAssemblyResolutions(results, newUnresolved @ unresolved)
|
|
|
|
/// Get information about referenced DLLs
|
|
member tcResolutions.GetAssemblyResolutions() = results
|
|
member tcResolutions.GetUnresolvedReferences() = unresolved
|
|
member tcResolutions.TryFindByOriginalReference(assemblyReference:AssemblyReference) = originalReferenceToResolution.TryFind assemblyReference.Text
|
|
member tcResolutions.TryFindByResolvedName(nm) = resolvedPathToResolution.TryFind nm
|
|
|
|
static member Resolve (tcConfig:TcConfig,assemblyList:AssemblyReference list) : TcAssemblyResolutions =
|
|
let resolved,unresolved =
|
|
if tcConfig.useMonoResolution then
|
|
assemblyList |> List.map tcConfig.ResolveLibWithDirectories, []
|
|
else
|
|
TcConfig.TryResolveLibsUsingMSBuildRules (tcConfig,assemblyList,rangeStartup,ReportErrors)
|
|
TcAssemblyResolutions(resolved,unresolved)
|
|
|
|
|
|
static member GetAllDllReferences (tcConfig:TcConfig) =
|
|
[ yield tcConfig.MscorlibDllReference()
|
|
//yield tcConfig.SystemDllReference()
|
|
if not tcConfig.compilingFslib then
|
|
yield tcConfig.CoreLibraryDllReference()
|
|
|
|
if tcConfig.framework then
|
|
for s in coreFramework do yield AssemblyReference(rangeStartup,s^".dll")
|
|
for s in extendedFramework do yield AssemblyReference(rangeStartup,s^".dll")
|
|
if tcConfig.useFsiAuxLib then
|
|
let name = Filename.concat tcConfig.fsharpBinariesDir (fsiaux()^".dll")
|
|
yield AssemblyReference(rangeStartup,name)
|
|
yield! tcConfig.referencedDLLs ]
|
|
|
|
static member SplitNonFoundationalResolutions (tcConfig:TcConfig) =
|
|
let assemblyList = TcAssemblyResolutions.GetAllDllReferences tcConfig
|
|
let resolutions = TcAssemblyResolutions.Resolve(tcConfig,assemblyList)
|
|
let frameworkDLLs,nonFrameworkReferences = resolutions.GetAssemblyResolutions() |> List.partition (fun r -> r.sysdir)
|
|
let unresolved = resolutions.GetUnresolvedReferences()
|
|
#if TRACK_DOWN_EXTRA_BACKSLASHES
|
|
frameworkDLLs |> List.iter(fun x ->
|
|
let path = x.resolvedPath
|
|
System.Diagnostics.Debug.Assert(not(path.Contains(@"\\")), "SplitNonFoundationalResolutions results in a non-canonical filename with extra backslashes: "^path)
|
|
)
|
|
nonFrameworkReferences |> List.iter(fun x ->
|
|
let path = x.resolvedPath
|
|
System.Diagnostics.Debug.Assert(not(path.Contains(@"\\")), "SplitNonFoundationalResolutions results in a non-canonical filename with extra backslashes: "^path)
|
|
)
|
|
#endif
|
|
#if DEBUG
|
|
let itFailed = ref false
|
|
let addedText = "\nIf you want to debug this right now, attach a debugger, and put a breakpoint in 'build.ml' near the text '!itFailed', and you can re-step through the assembly resolution logic."
|
|
unresolved
|
|
|> List.iter (fun (UnresolvedReference(referenceText,ranges)) ->
|
|
if referenceText.Contains("mscorlib") then
|
|
System.Diagnostics.Debug.Assert(false, sprintf "whoops, did not resolve mscorlib: '%s'%s" referenceText addedText)
|
|
itFailed := true)
|
|
frameworkDLLs
|
|
|> List.iter (fun x ->
|
|
if not(System.IO.Path.IsPathRooted(x.resolvedPath)) then
|
|
System.Diagnostics.Debug.Assert(false, sprintf "frameworkDLL should be absolute path: '%s'%s" x.resolvedPath addedText)
|
|
itFailed := true)
|
|
nonFrameworkReferences
|
|
|> List.iter (fun x ->
|
|
if not(System.IO.Path.IsPathRooted(x.resolvedPath)) then
|
|
System.Diagnostics.Debug.Assert(false, sprintf "nonFrameworkReference should be absolute path: '%s'%s" x.resolvedPath addedText)
|
|
itFailed := true)
|
|
if !itFailed then
|
|
// idea is, put a breakpoint here and then step through
|
|
let assemblyList = TcAssemblyResolutions.GetAllDllReferences tcConfig
|
|
let resolutions = TcAssemblyResolutions.Resolve(tcConfig,assemblyList)
|
|
let frameworkDLLs,nonFrameworkReferences = resolutions.GetAssemblyResolutions() |> List.partition (fun r -> r.sysdir)
|
|
()
|
|
#endif
|
|
frameworkDLLs,nonFrameworkReferences,unresolved
|
|
|
|
static member BuildFromPriorResolutions (tcConfig:TcConfig,resolutions) =
|
|
let references = resolutions |> List.map (fun r -> r.originalReference)
|
|
TcAssemblyResolutions.Resolve(tcConfig,references)
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Typecheck and optimization environments on disk
|
|
//--------------------------------------------------------------------------
|
|
open Pickle
|
|
|
|
let IsSignatureDataResource r = String.hasPrefix r.resourceName FSharpSignatureDataResourceName
|
|
let IsOptDataResource r = String.hasPrefix r.resourceName FSharpOptimizationDataResourceName
|
|
let GetSignatureDataResourceName r = String.dropPrefix (String.dropPrefix r.resourceName FSharpSignatureDataResourceName) "."
|
|
let GetOptDataResourceName r = String.dropPrefix (String.dropPrefix r.resourceName FSharpOptimizationDataResourceName) "."
|
|
|
|
let IsReflectedDefinitionsResource r = String.hasPrefix r.resourceName Sreflect.pickledDefinitionsResourceNameBase
|
|
|
|
let UnpickleFromResource file m u sref r =
|
|
match r.resourceWhere with
|
|
| Resource_local b -> unpickle_obj_with_dangling_ccus file sref u (b())
|
|
| _-> error(InternalError("UnpickleFromResource",m))
|
|
|
|
let MakeILResource rname bytes =
|
|
{ resourceName = rname;
|
|
resourceWhere = Resource_local (fun () -> bytes);
|
|
resourceAccess = Resource_public;
|
|
resourceCustomAttrs = mk_custom_attrs [] }
|
|
|
|
let PickleToResource file g scope rname p x =
|
|
{ resourceName = rname;
|
|
resourceWhere = (let bytes = pickle_obj_with_dangling_ccus file g scope p x in Resource_local (fun () -> bytes));
|
|
resourceAccess = Resource_public;
|
|
resourceCustomAttrs = mk_custom_attrs [] }
|
|
|
|
|
|
let GetSignatureData file m sref r : PickledDataWithReferences<PickledModuleInfo> =
|
|
UnpickleFromResource file m UnpickleModuleInfo sref r
|
|
|
|
let WriteSignatureData (tcConfig:TcConfig,tcGlobals,exportRemapping,ccu:ccu,file) : ILResource =
|
|
let mspec = ccu.Contents
|
|
if !verboseStamps then
|
|
dprintf "Signature data before remap:\n%s\n" (Layout.showL (Layout.squashTo 192 (EntityL mspec)));
|
|
dprintf "---------------------- START OF APPLYING EXPORT REMAPPING TO SIGNATURE DATA------------\n";
|
|
let mspec = ApplyExportRemappingToEntity tcGlobals exportRemapping mspec
|
|
if !verboseStamps then
|
|
dprintf "---------------------- END OF APPLYING EXPORT REMAPPING TO SIGNATURE DATA------------\n";
|
|
dprintf "Signature data after remap:\n%s\n" (Layout.showL (Layout.squashTo 192 (EntityL mspec)));
|
|
PickleToResource file tcGlobals ccu (FSharpSignatureDataResourceName^"."^ccu.AssemblyName) PickleModuleInfo
|
|
{ mspec=mspec;
|
|
compile_time_working_dir=tcConfig.implicitIncludeDir;
|
|
usesQuotations = ccu.UsesQuotations }
|
|
|
|
let GetOptimizationData file m sref ca =
|
|
UnpickleFromResource file m Opt.u_lazy_modul_info sref ca
|
|
|
|
let WriteOptData tcGlobals file (ccu,modulInfo) =
|
|
if verbose then dprintf "Optimization data after remap:\n%s\n" (Layout.showL (Layout.squashTo 192 (Opt.moduleInfoL modulInfo)));
|
|
PickleToResource file tcGlobals ccu (FSharpOptimizationDataResourceName^"."^ccu.AssemblyName) Opt.p_lazy_modul_info modulInfo
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Names to match up refs and defs for assemblies and modules
|
|
//--------------------------------------------------------------------------
|
|
|
|
let GetNameOfScopeRef sref =
|
|
match sref with
|
|
| ScopeRef_local -> "<local>"
|
|
| ScopeRef_module mref -> mref.Name
|
|
| ScopeRef_assembly aref -> aref.Name
|
|
|
|
let GetNameOfILModule m = if module_is_mainmod m then assname_of_mainmod m else m.modulName
|
|
|
|
|
|
let MakeScopeRefForIlModule tcConfig ilModule =
|
|
if module_is_mainmod ilModule then
|
|
ScopeRef_assembly (assref_for_mainmod ilModule)
|
|
else
|
|
ScopeRef_module (modref_for_modul ilModule)
|
|
|
|
let GetCustomAttributesOfIlModule (ilModule:ILModuleDef) =
|
|
dest_custom_attrs (match ilModule.Manifest with Some m -> m.CustomAttrs | None -> ilModule.CustomAttrs)
|
|
|
|
let GetAutoOpenAttributes(ilModule) =
|
|
ilModule |> GetCustomAttributesOfIlModule |> List.choose TryFindAutoOpenAttr
|
|
|
|
let GetInternalsVisibleToAttributes ilModule =
|
|
ilModule |> GetCustomAttributesOfIlModule |> List.choose TryFindInternalsVisibleToAttr
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Relink blobs of saved data by fixing up ccus.
|
|
//--------------------------------------------------------------------------
|
|
|
|
type ImportedBinary =
|
|
{ FileName: string;
|
|
IsFSharpBinary: bool;
|
|
RawMetadata: ILModuleDef;
|
|
ILAssemblyRefs : ILAssemblyRef list;
|
|
ILScopeRef: ILScopeRef }
|
|
|
|
type ImportedAssembly =
|
|
{ ILScopeRef: ILScopeRef;
|
|
FSharpViewOfMetadata: ccu;
|
|
AssemblyAutoOpenAttributes: string list;
|
|
AssemblyInternalsVisibleToAttributes: string list;
|
|
FSharpOptimizationData : Lazy<Option<Opt.LazyModuleInfo>> }
|
|
|
|
type AvailableImportedAssembly =
|
|
| ResolvedImportedAssembly of ImportedAssembly
|
|
| UnresolvedImportedAssembly of string
|
|
|
|
let availableToOptionalCcu = function
|
|
| ResolvedCcu(ccu) -> Some(ccu)
|
|
| UnresolvedCcu(assemblyName) -> None
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// TcConfigProvider
|
|
//--------------------------------------------------------------------------
|
|
|
|
type TcConfigProvider =
|
|
| TcConfigProvider of (unit -> TcConfig)
|
|
member x.Get() = (let (TcConfigProvider(f)) = x in f())
|
|
static member Constant(tcConfig) = TcConfigProvider(fun () -> tcConfig)
|
|
static member BasedOnMutableBuilder(tcConfigB) = TcConfigProvider(fun () -> TcConfig.Create(tcConfigB,validate=false))
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// TcImports
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
/// Tables of imported assemblies.
|
|
[<Sealed>]
|
|
type TcImports(tcConfigP:TcConfigProvider,initialResolutions:TcAssemblyResolutions, importsBase:TcImports option,ilGlobalsOpt) =
|
|
let mutable resolutions = initialResolutions
|
|
|
|
let mutable importsBase : TcImports option = importsBase
|
|
let mutable dllInfos: ImportedBinary list = []
|
|
let mutable dllTable: ImportedBinary NameMap = NameMap.empty
|
|
let mutable ccuInfos: ImportedAssembly list = []
|
|
let mutable ccuTable: ImportedAssembly NameMap = NameMap.empty
|
|
let mutable disposeActions = []
|
|
let mutable originalReferenceToResolution : Map<string,AssemblyResolution> = Map.empty
|
|
let mutable resolvedPathToResolution : Map<string,AssemblyResolution> = Map.empty
|
|
#if DEBUG
|
|
let mutable disposed = false
|
|
#endif
|
|
let mutable ilGlobalsOpt = ilGlobalsOpt
|
|
let mutable tcGlobals = None
|
|
|
|
let CheckDisposed() =
|
|
#if DEBUG
|
|
if disposed then failwith "Use of Disposed TcConfig"
|
|
#else
|
|
()
|
|
#endif
|
|
|
|
member tcImports.SetBase(baseTcImports) =
|
|
CheckDisposed()
|
|
importsBase <- Some(baseTcImports)
|
|
|
|
member private tcImports.Base
|
|
with get() =
|
|
CheckDisposed()
|
|
importsBase
|
|
|
|
member tcImports.CcuTable
|
|
with get() =
|
|
CheckDisposed()
|
|
ccuTable
|
|
|
|
member private tcImports.DllTable
|
|
with get() =
|
|
CheckDisposed()
|
|
dllTable
|
|
|
|
member tcImports.RegisterCcu(ccuInfo) =
|
|
CheckDisposed()
|
|
ccuInfos <- ccuInfos ++ ccuInfo;
|
|
// Assembly Ref Resolution: remove this use of ccu.AssemblyName
|
|
ccuTable <- NameMap.add (ccuInfo.FSharpViewOfMetadata.AssemblyName) ccuInfo ccuTable
|
|
|
|
member tcImports.RegisterDll(dllInfo) =
|
|
CheckDisposed()
|
|
dllInfos <- dllInfos ++ dllInfo;
|
|
dllTable <- NameMap.add (GetNameOfScopeRef dllInfo.ILScopeRef) dllInfo dllTable
|
|
|
|
member tcImports.GetDllInfos() =
|
|
CheckDisposed()
|
|
match importsBase with
|
|
| Some(importsBase)-> importsBase.GetDllInfos() @ dllInfos
|
|
| None -> dllInfos
|
|
|
|
member tcImports.FindDllInfo (m,assemblyName) =
|
|
CheckDisposed()
|
|
let rec look(t:TcImports) =
|
|
match NameMap.tryfind assemblyName t.DllTable with
|
|
| Some res -> Some(res)
|
|
| None ->
|
|
match t.Base with
|
|
| Some t2 -> look(t2)
|
|
| None -> None
|
|
match look(tcImports) with
|
|
| Some res -> res
|
|
| None ->
|
|
tcImports.ImplicitLoadIfAllowed(m,assemblyName);
|
|
match look(tcImports) with
|
|
| Some res -> res
|
|
| None -> error(Error("could not resolve assembly "^assemblyName,m))
|
|
|
|
|
|
member tcImports.FindDllInfoFromAssemblyRef(m,assref:ILAssemblyRef) =
|
|
CheckDisposed()
|
|
tcImports.FindDllInfo(m,assref.Name)
|
|
|
|
|
|
member tcImports.GetCcuInfos() =
|
|
CheckDisposed()
|
|
match importsBase with
|
|
| Some(importsBase)-> importsBase.GetCcuInfos() @ ccuInfos
|
|
| None -> ccuInfos
|
|
|
|
member tcImports.GetCcusInDeclOrder() =
|
|
CheckDisposed()
|
|
List.map (fun x -> x.FSharpViewOfMetadata) (tcImports.GetCcuInfos())
|
|
|
|
// This is the main "assembly reference --> assembly" resolution routine.
|
|
// We parameterize by a fallback resolution function that will go and look for DLLs matching the assembly name
|
|
// in the include search paths.
|
|
member tcImports.FindCcuInfo (m,assemblyName) =
|
|
CheckDisposed()
|
|
let rec look (t:TcImports) =
|
|
match NameMap.tryfind assemblyName t.CcuTable with
|
|
| Some res -> Some(res)
|
|
| None ->
|
|
match t.Base with
|
|
| Some t2 -> look t2
|
|
| None -> None
|
|
|
|
match look(tcImports) with
|
|
| Some res -> ResolvedImportedAssembly(res)
|
|
| None ->
|
|
tcImports.ImplicitLoadIfAllowed(m,assemblyName);
|
|
match look(tcImports) with
|
|
| Some res -> ResolvedImportedAssembly(res)
|
|
| None -> UnresolvedImportedAssembly(assemblyName)
|
|
|
|
|
|
member tcImports.FindCcu(m,assemblyName) =
|
|
CheckDisposed()
|
|
match tcImports.FindCcuInfo(m,assemblyName) with
|
|
| ResolvedImportedAssembly(importedAssembly) -> ResolvedCcu(importedAssembly.FSharpViewOfMetadata)
|
|
| UnresolvedImportedAssembly(assemblyName) -> UnresolvedCcu(assemblyName)
|
|
|
|
member tcImports.FindCcuFromAssemblyRef(m,assref:ILAssemblyRef) =
|
|
CheckDisposed()
|
|
match tcImports.FindCcuInfo(m,assref.Name) with
|
|
| ResolvedImportedAssembly(importedAssembly) -> ResolvedCcu(importedAssembly.FSharpViewOfMetadata)
|
|
| UnresolvedImportedAssembly(assemblyName) -> UnresolvedCcu(assref.QualifiedName)
|
|
|
|
member tcImports.AssemblyLoader =
|
|
Import.AssemblyLoader (fun (m,assref) -> tcImports.FindCcuFromAssemblyRef(m,assref))
|
|
|
|
member tcImports.AttachDisposeAction(action) =
|
|
CheckDisposed()
|
|
disposeActions <- action :: disposeActions
|
|
|
|
override obj.ToString() =
|
|
sprintf "tcImports = \n dllInfos=%A\n dllTable=%A\n ccuInfos=%A\n ccuTable=%A\n Base=%s\n"
|
|
dllInfos
|
|
dllTable
|
|
ccuInfos
|
|
ccuTable
|
|
(match importsBase with None-> "None" | Some(importsBase) -> importsBase.ToString())
|
|
|
|
|
|
// Note: the returned binary reader is associated with the tcImports, i.e. when the tcImports are closed
|
|
// then the reader is closed.
|
|
member tcImports.OpenIlBinaryModule(syslib,filename,m) =
|
|
try
|
|
CheckDisposed()
|
|
let tcConfig = tcConfigP.Get()
|
|
let pdbPathOption =
|
|
// We open the pdb file if one exists parallel to the binary we
|
|
// are reading, so that --standalone will preserve debug information.
|
|
if tcConfig.openDebugInformationForLaterStaticLinking then
|
|
let pdbDir = (try Filename.dirname filename with _ -> ".")
|
|
let pdbFile = (try Filename.chop_extension filename with _ -> filename)^".pdb"
|
|
if Internal.Utilities.FileSystem.File.SafeExists pdbFile then
|
|
if verbose then dprintf "reading PDB file %s from directory %s\n" pdbFile pdbDir;
|
|
Some pdbDir
|
|
else
|
|
None
|
|
else
|
|
None
|
|
|
|
|
|
let ilBinaryReader = OpenILBinary(filename,tcConfig.optimizeForMemory,tcConfig.openBinariesInMemory,ilGlobalsOpt,pdbPathOption,tcConfig.mscorlibAssemblyName)
|
|
|
|
tcImports.AttachDisposeAction(fun _ -> Ilread.CloseILModuleReader ilBinaryReader);
|
|
ilBinaryReader.ILModuleDef, ilBinaryReader.ILAssemblyRefs
|
|
with e ->
|
|
error(Error(sprintf "Error opening binary file '%s': %s" filename e.Message,m))
|
|
|
|
|
|
|
|
(* auxModTable is used for multi-module assemblies *)
|
|
member tcImports.MkLoaderForMultiModuleIlAssemblies m syslib =
|
|
CheckDisposed()
|
|
let auxModTable = Hashtbl.create 10
|
|
fun viewedScopeRef ->
|
|
|
|
let tcConfig = tcConfigP.Get()
|
|
match viewedScopeRef with
|
|
| ScopeRef_module modref ->
|
|
let key = modref.Name
|
|
if not (auxModTable.ContainsKey(key)) then
|
|
let resolution = tcConfig.ResolveLibWithDirectories(AssemblyReference(m,key))
|
|
let ilModule,_ = tcImports.OpenIlBinaryModule(syslib,resolution.resolvedPath,m)
|
|
auxModTable.[key] <- ilModule
|
|
auxModTable.[key]
|
|
|
|
| _ ->
|
|
error(InternalError("Unexpected ScopeRef_local or ScopeRef_assembly in exported type table",m))
|
|
|
|
member tcImports.IsAlreadyRegistered nm =
|
|
CheckDisposed()
|
|
tcImports.GetDllInfos() |> List.exists (fun dll ->
|
|
match dll.ILScopeRef with
|
|
| ScopeRef_assembly a -> a.Name = nm
|
|
| _ -> false)
|
|
|
|
member tcImports.GetImportMap() =
|
|
CheckDisposed()
|
|
new Import.ImportMap (tcImports.GetTcGlobals(),tcImports.AssemblyLoader)
|
|
|
|
// Note the tcGlobals are only available once mscorlib and fslib have been established. For TcImports,
|
|
// they are logically only needed when converting AbsIL data structures into F# data structures, and
|
|
// when converting AbsIL types in particular, since these types are normalized through the tables
|
|
// in the tcGlobals (E.g. normalizing 'System.Int32' to 'int'). On the whole ImportIlAssembly doesn't
|
|
// actually convert AbsIL types - it only converts the outer shell of type definitions - the vast majority of
|
|
// types such as those in method signatures are currently converted on-demand. However ImportILAssembly does have to
|
|
// convert the types that are constraints in generic parameters, which was the original motivation for making sure that
|
|
// ImportILAssembly had a tcGlobals available when it really needs it.
|
|
member tcImports.GetTcGlobals() =
|
|
CheckDisposed()
|
|
match tcGlobals with
|
|
| Some(g) -> g
|
|
| None ->
|
|
match importsBase with
|
|
| Some(b) -> b.GetTcGlobals()
|
|
| None -> failwith "unreachable: GetGlobals"
|
|
|
|
member private tcImports.SetILGlobals(ilg) =
|
|
CheckDisposed()
|
|
ilGlobalsOpt <- Some(ilg)
|
|
|
|
member private tcImports.SetTcGlobals(g) =
|
|
CheckDisposed()
|
|
tcGlobals <- Some(g)
|
|
|
|
// Add a referenced assembly
|
|
//
|
|
// Retargetable assembly refs are required for binaries that must run
|
|
// against DLLs supported by multiple publishers. For example
|
|
// Compact Framework binaries must use this. However it is not
|
|
// clear when else it is required, e.g. for Mono.
|
|
|
|
member tcImports.PrepareToImportReferencedIlDll syslib m filename (dllinfo:ImportedBinary) =
|
|
CheckDisposed()
|
|
let tcConfig = tcConfigP.Get()
|
|
let ilModule = dllinfo.RawMetadata
|
|
let sref = dllinfo.ILScopeRef
|
|
let aref =
|
|
match sref with
|
|
| ScopeRef_assembly aref -> aref
|
|
| _ -> error(InternalError("PrepareToImportReferencedIlDll: cannot reference .NET netmodules directly, reference the containing assembly instead",m))
|
|
|
|
let nm = aref.Name
|
|
if verbose then dprintn ("Converting IL assembly to F# data structures "^nm);
|
|
let auxModuleLoader = tcImports.MkLoaderForMultiModuleIlAssemblies m syslib
|
|
let ccu = Import.ImportIlAssembly(tcImports.GetImportMap,m,auxModuleLoader,sref,tcConfig.implicitIncludeDir, Some filename,ilModule)
|
|
let ccuinfo =
|
|
{ FSharpViewOfMetadata=ccu;
|
|
ILScopeRef = sref;
|
|
AssemblyAutoOpenAttributes = GetAutoOpenAttributes(ilModule);
|
|
AssemblyInternalsVisibleToAttributes = GetInternalsVisibleToAttributes(ilModule);
|
|
FSharpOptimizationData = notlazy None }
|
|
tcImports.RegisterCcu(ccuinfo);
|
|
let phase2 () = [ResolvedImportedAssembly(ccuinfo)]
|
|
phase2
|
|
|
|
member tcImports.PrepareToImportReferencedFSharpDll syslib m filename (dllinfo:ImportedBinary) =
|
|
CheckDisposed()
|
|
let tcConfig = tcConfigP.Get()
|
|
tcConfig.CheckFSharpBinary(filename,dllinfo.ILAssemblyRefs,m)
|
|
let ilModule = dllinfo.RawMetadata
|
|
let sref = dllinfo.ILScopeRef
|
|
let modname = GetNameOfScopeRef sref
|
|
if verbose then dprintn ("Converting F# assembly to F# data structures "^(GetNameOfScopeRef sref));
|
|
let attrs = GetCustomAttributesOfIlModule ilModule
|
|
assert (List.exists IsSignatureDataVersionAttr attrs);
|
|
if verbose then dprintn ("Relinking interface info from F# assembly "^modname);
|
|
let resources = dest_resources ilModule.modulResources
|
|
assert (List.exists IsSignatureDataResource resources);
|
|
let optDataFromResource =
|
|
resources
|
|
|> List.choose (fun r -> if IsOptDataResource r then Some(GetOptDataResourceName r,r) else None)
|
|
let ccuRawDataAndInfos =
|
|
resources
|
|
|> List.filter IsSignatureDataResource
|
|
|> List.map (fun iresource ->
|
|
let ccuName = GetSignatureDataResourceName iresource
|
|
let data = GetSignatureData filename m sref iresource
|
|
|
|
// Look for optimization data in a file
|
|
let optDataFromFile =
|
|
let optDataFileName = (Filename.chop_extension filename)^".optdata"
|
|
if Internal.Utilities.FileSystem.File.SafeExists optDataFileName then
|
|
try Some(ccuName,MakeILResource optDataFileName (File.ReadAllBytes optDataFileName))
|
|
with _ -> None
|
|
else None
|
|
|
|
let optDatas =
|
|
// If F# optData is written to file, the DLL still contains "essential" optData - i.e. the must inline information.
|
|
// If we find optData in a file, we should use that one in preference to resource optData.
|
|
// We choose one or the other.
|
|
match optDataFromFile,optDataFromResource with
|
|
| None ,[] -> warning(Error(Printf.sprintf "No optimization information found for compilation unit '%s'" ccuName,m)); Map.empty
|
|
| Some optData,_ -> Map.of_list [optData] // prefer optData from file if available, since it implies DLL optData is limitted to "essential"
|
|
| None ,optDatas -> Map.of_list optDatas // Espect this route, optData from file is being disabled (but kept around).
|
|
|
|
let minfo : PickledModuleInfo = data.RawData
|
|
let mspec = minfo.mspec
|
|
|
|
|
|
// Adjust where the code for known F# libraries live relative to the installation of F#
|
|
let code_dir =
|
|
let dir = minfo.compile_time_working_dir
|
|
let knownLibraryLocation = @"src\fsharp\" // Help highlighting... "
|
|
let knownLibarySuffixes =
|
|
[ @"FSharp.Core";
|
|
@"FSharp.PowerPack";
|
|
@"FSharp.PowerPack.Linq";
|
|
@"FSharp.PowerPack.Metadata" ]
|
|
match knownLibarySuffixes |> List.tryfind (fun x -> dir.EndsWith(knownLibraryLocation + x,StringComparison.OrdinalIgnoreCase)) with
|
|
| None ->
|
|
dir
|
|
| Some libSuffix ->
|
|
// chop off 'FSharp.Core'
|
|
let dir = dir.[0..dir.Length-1-libSuffix.Length]
|
|
// chop off 'src\fsharp\'
|
|
let dir = dir.[0..dir.Length-1-knownLibraryLocation.Length]
|
|
// add "..\lib\FSharp.Core" to the F# binaries directory
|
|
let dir = Path.Combine(Path.Combine(tcConfig.fsharpBinariesDir,@"..\lib"),libSuffix)
|
|
dir
|
|
|
|
let ccu =
|
|
new_ccu ccuName
|
|
{ ccu_scoref=sref;
|
|
ccu_stamp = new_stamp();
|
|
ccu_filename = Some filename;
|
|
ccu_qname= Some(sref.QualifiedName);
|
|
ccu_code_dir = code_dir; (* note: in some cases we fix up this information later *)
|
|
ccu_fsharp=true;
|
|
ccu_contents = mspec;
|
|
ccu_usesQuotations = minfo.usesQuotations;
|
|
ccu_forwarders = lazy Map.empty }
|
|
|
|
let optdata =
|
|
lazy
|
|
(match Map.tryfind ccuName optDatas with
|
|
| None ->
|
|
if verbose then dprintf "*** no optimization data for CCU %s, was DLL compiled with --no-optimization-data??\n" ccuName;
|
|
None
|
|
| Some info ->
|
|
let data = GetOptimizationData filename m sref info
|
|
let res = data.OptionalFixup(fun nm -> availableToOptionalCcu(tcImports.FindCcu(m,nm)))
|
|
if verbose then dprintf "found optimization data for CCU %s\n" ccuName;
|
|
Some res)
|
|
data,{ FSharpViewOfMetadata=ccu;
|
|
AssemblyAutoOpenAttributes = GetAutoOpenAttributes(ilModule);
|
|
AssemblyInternalsVisibleToAttributes = GetInternalsVisibleToAttributes(ilModule);
|
|
FSharpOptimizationData=optdata;
|
|
ILScopeRef = sref } )
|
|
|
|
// Register all before relinking to cope with mutually-referential ccus
|
|
ccuRawDataAndInfos |> List.iter (snd >> tcImports.RegisterCcu);
|
|
let phase2 () =
|
|
(* Relink *)
|
|
(* dprintf "Phase2: %s\n" filename; REMOVE DIAGNOSTICS *)
|
|
ccuRawDataAndInfos |> List.iter (fun (data,_) -> data.OptionalFixup(fun nm -> availableToOptionalCcu(tcImports.FindCcu(m,nm))) |> ignore);
|
|
ccuRawDataAndInfos |> List.map snd |> List.map ResolvedImportedAssembly
|
|
phase2
|
|
|
|
|
|
member tcImports.RegisterAndPrepareToImportReferencedDll warnIfAlreadyLoaded (r:AssemblyResolution) : _*(unit -> AvailableImportedAssembly list)=
|
|
CheckDisposed()
|
|
let tcConfig = tcConfigP.Get()
|
|
let m = r.originalReference.Range
|
|
let filename = r.resolvedPath
|
|
let syslib = r.sysdir
|
|
let ilModule,ilAssemblyRefs = tcImports.OpenIlBinaryModule(syslib,filename,m)
|
|
|
|
let modname = GetNameOfILModule ilModule
|
|
if tcImports.IsAlreadyRegistered modname then
|
|
let dllinfo = tcImports.FindDllInfo(m,modname)
|
|
let phase2() = [tcImports.FindCcuInfo(m,modname)]
|
|
dllinfo,phase2
|
|
else
|
|
let sref = MakeScopeRefForIlModule tcConfig ilModule
|
|
let dllinfo = {RawMetadata=ilModule;
|
|
FileName=filename;
|
|
IsFSharpBinary=true;
|
|
ILScopeRef = sref;
|
|
ILAssemblyRefs = ilAssemblyRefs }
|
|
tcImports.RegisterDll(dllinfo);
|
|
let attrs = GetCustomAttributesOfIlModule ilModule
|
|
let phase2 =
|
|
if (List.exists IsSignatureDataVersionAttr attrs) then
|
|
if not (List.exists (IsMatchingSignatureDataVersionAttr (IL.parse_version Ilxconfig.version)) attrs) then
|
|
errorR(Error("The F#-compiled DLL '"^filename^"' needs to be recompiled to be used with this version of F#",m));
|
|
tcImports.PrepareToImportReferencedIlDll syslib m filename dllinfo
|
|
else
|
|
tcImports.PrepareToImportReferencedFSharpDll syslib m filename dllinfo
|
|
else
|
|
tcImports.PrepareToImportReferencedIlDll syslib m filename dllinfo
|
|
dllinfo,phase2
|
|
|
|
member tcImports.RegisterAndImportReferencedAssemblies warnIfAlreadyLoaded (nms:AssemblyResolution list) =
|
|
CheckDisposed()
|
|
|
|
let dllinfos,phase2s =
|
|
nms |> List.map (tcImports.RegisterAndPrepareToImportReferencedDll warnIfAlreadyLoaded)
|
|
|> List.unzip
|
|
let ccuinfos = (List.collect (fun phase2 -> phase2()) phase2s)
|
|
dllinfos,ccuinfos
|
|
|
|
member tcImports.DoRegisterAndImportReferencedAssemblies nms =
|
|
CheckDisposed()
|
|
tcImports.RegisterAndImportReferencedAssemblies true nms |> ignore
|
|
|
|
member tcImports.ImplicitLoadIfAllowed(m,assemblyName) =
|
|
CheckDisposed()
|
|
// If the user is asking for the default framework then also try to resolve other implicit assemblies as they are discovered.
|
|
// Using this flag to mean 'allow implicit discover of assemblies'.
|
|
let tcConfig = tcConfigP.Get()
|
|
if tcConfig.implicitlyResolveAssemblies then
|
|
let tryFile speculativeFileName =
|
|
let foundFile =
|
|
try Some(tcImports.ResolveLibFile (AssemblyReference(m,speculativeFileName),ResolveLibFileMode.Speculative))
|
|
with
|
|
// Don't re-report the load error
|
|
| AssemblyNotResolved _
|
|
| FileNameNotResolved _ -> None
|
|
match foundFile with
|
|
| None -> None
|
|
| Some res ->
|
|
//if not tcConfig.noFeedback then dprintf "Implicitly referencing '%s'...\n" fileName;
|
|
tcImports.DoRegisterAndImportReferencedAssemblies [res]
|
|
Some()
|
|
|
|
match tryFile (assemblyName^".dll") with
|
|
| Some() -> ()
|
|
| None -> tryFile (assemblyName^".exe") |> ignore
|
|
|
|
|
|
member tcImports.TryResolveLibFile (assemblyReference:AssemblyReference,mode:ResolveLibFileMode): OperationResult<AssemblyResolution> =
|
|
let tcConfig = tcConfigP.Get()
|
|
// First try the prior resolutions map.
|
|
match resolutions.TryFindByOriginalReference assemblyReference with
|
|
| Some(assemblyResolution) ->
|
|
ResultD(assemblyResolution)
|
|
| None ->
|
|
match resolutions.TryFindByResolvedName assemblyReference.Text with
|
|
| Some(assemblyResolution) ->
|
|
ResultD(assemblyResolution)
|
|
| None ->
|
|
if tcConfigP.Get().useMonoResolution then
|
|
try
|
|
ResultD(tcConfig.ResolveLibWithDirectories assemblyReference)
|
|
with e ->
|
|
ErrorD(e)
|
|
else
|
|
// This is a previously unencounterd assembly. Resolve it and add it to the list.
|
|
// But don't cache resolution failures because the assembly may appear on the disk later.
|
|
let resolved,unresolved = TcConfig.TryResolveLibsUsingMSBuildRules(tcConfig,[ assemblyReference ],assemblyReference.Range,mode)
|
|
match resolved,unresolved with
|
|
| (assemblyResolution::_,_) ->
|
|
resolutions <- resolutions.AddResolutionResults(resolved)
|
|
ResultD(assemblyResolution)
|
|
| (_,_::_) ->
|
|
resolutions <- resolutions.AddUnresolvedReferences(unresolved)
|
|
ErrorD(AssemblyNotResolved(assemblyReference.Text,assemblyReference.Range))
|
|
| [],[] ->
|
|
// Note, if mode=ResolveLibFileMode.Speculative and the resolution failed then TryResolveLibsUsingMSBuildRules returns
|
|
// the empty list and we convert the failure into an AssemblyNotResolved here.
|
|
ErrorD(AssemblyNotResolved(assemblyReference.Text,assemblyReference.Range))
|
|
|
|
/// Do TryResolveLibFile and commit the result
|
|
|
|
member tcImports.ResolveLibFile (assemblyReference,mode) =
|
|
let opResult = tcImports.TryResolveLibFile(assemblyReference,mode)
|
|
CommitOperationResult opResult
|
|
|
|
|
|
static member BuildFrameworkTcImports (tcConfigP:TcConfigProvider,frameworkDLLs) =
|
|
use t = Trace.Call("Build","BuildFrameworkTcImports", fun _->"")
|
|
|
|
let tcConfig = tcConfigP.Get()
|
|
let tcResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(tcConfig,frameworkDLLs)
|
|
|
|
// mscorlib gets loaded first.
|
|
let mscorlibReference = tcConfig.MscorlibDllReference()
|
|
|
|
let frameworkTcImports = new TcImports(tcConfigP,tcResolutions,None,None)
|
|
|
|
let sysCcu =
|
|
let mscorlibResolution = tcConfig.ResolveLibWithDirectories(mscorlibReference)
|
|
//printfn "mscorlibResolution= %s" mscorlibResolution.resolvedPath
|
|
match frameworkTcImports.RegisterAndImportReferencedAssemblies false [mscorlibResolution] with
|
|
| (_, [ResolvedImportedAssembly(sysCcu)]) -> sysCcu
|
|
| _ -> error(InternalError("BuildFoundationalTcImports: no sysCcu for "^mscorlibReference.Text,rangeStartup))
|
|
let ilGlobals = IL.mk_ILGlobals sysCcu.FSharpViewOfMetadata.ILScopeRef (Some tcConfig.mscorlibAssemblyName)
|
|
frameworkTcImports.SetILGlobals ilGlobals
|
|
|
|
// Load the rest of the framework DLLs all at once (they may be mutually recursive)
|
|
frameworkTcImports.DoRegisterAndImportReferencedAssemblies (tcResolutions.GetAssemblyResolutions())
|
|
|
|
let fslibCcu =
|
|
if tcConfig.compilingFslib then
|
|
// When compiling FSharp.Core.dll, the fslibCcu reference to FSharp.Core.dll is a delayed ccu thunk fixed up during type checking
|
|
let fslibCcu = CcuThunk.CreateDelayed(GetFSharpCoreLibraryName())
|
|
fslibCcu
|
|
else
|
|
let fslibCcuInfo =
|
|
let coreLibraryReference = tcConfig.CoreLibraryDllReference()
|
|
//printfn "coreLibraryReference = %A" coreLibraryReference
|
|
match tcResolutions.TryFindByOriginalReference(coreLibraryReference) with
|
|
| Some coreLibraryResolution ->
|
|
//printfn "coreLibraryResolution = '%s'" coreLibraryResolution.resolvedPath
|
|
match frameworkTcImports.RegisterAndImportReferencedAssemblies false [coreLibraryResolution] with
|
|
| (_, [ResolvedImportedAssembly(fslibCcuInfo) ]) -> fslibCcuInfo
|
|
| _ ->
|
|
error(InternalError("BuildFrameworkTcImports: no successful import of "^coreLibraryResolution.resolvedPath,coreLibraryResolution.originalReference.Range))
|
|
| None ->
|
|
error(InternalError(sprintf "BuildFrameworkTcImports: no resolution of '%s'" coreLibraryReference.Text,rangeStartup))
|
|
Msilxlib.ilxLibraryAssemRef :=
|
|
(let scoref = fslibCcuInfo.ILScopeRef
|
|
match scoref with
|
|
| ScopeRef_assembly aref -> Some aref
|
|
| ScopeRef_local | ScopeRef_module _ -> error(InternalError("fslib_assembly_ref: not ScopeRef_assembly",rangeStartup)));
|
|
fslibCcuInfo.FSharpViewOfMetadata
|
|
|
|
// can't access system tuples on frameworks < v4.0
|
|
match ilGlobals.mscorlib_scoref.AssemblyRef.Version with
|
|
| Some(v1,_,_,_) when v1 < 4us ->
|
|
Microsoft.FSharp.Compiler.Tastops.use_40_System_Types <- false
|
|
| _ -> ()
|
|
|
|
// OK, now we have both mscorlib.dll and FSharp.Core.dll we can create TcGlobals
|
|
let tcGlobals = mk_tcGlobals(tcConfig.compilingFslib,sysCcu.FSharpViewOfMetadata,ilGlobals,fslibCcu,tcConfig.implicitIncludeDir,tcConfig.mlCompatibility, Microsoft.FSharp.Compiler.Tastops.use_40_System_Types)
|
|
#if DEBUG
|
|
// the global_g reference cell is used only for debug printing
|
|
global_g := Some tcGlobals;
|
|
#endif
|
|
// do this prior to parsing, since parsing IL assembly code may refer to mscorlib
|
|
Microsoft.FSharp.Compiler.AbstractIL.Internal.AsciiConstants.parse_ilGlobals := tcGlobals.ilg;
|
|
frameworkTcImports.SetTcGlobals(tcGlobals)
|
|
tcGlobals,frameworkTcImports
|
|
|
|
static member BuildNonFrameworkTcImports (tcConfigP:TcConfigProvider,tcGlobals:TcGlobals, baseTcImports,nonFrameworkReferences) =
|
|
let tcConfig = tcConfigP.Get()
|
|
let tcResolutions = TcAssemblyResolutions.BuildFromPriorResolutions(tcConfig,nonFrameworkReferences)
|
|
let references = tcResolutions.GetAssemblyResolutions()
|
|
let tcImports = new TcImports(tcConfigP,tcResolutions,Some baseTcImports, Some tcGlobals.ilg)
|
|
tcImports.DoRegisterAndImportReferencedAssemblies references;
|
|
tcImports
|
|
|
|
|
|
static member BuildTcImports(tcConfigP:TcConfigProvider) =
|
|
let tcConfig = tcConfigP.Get()
|
|
//let foundationalTcImports,tcGlobals = TcImports.BuildFoundationalTcImports(tcConfigP)
|
|
let frameworkDLLs,nonFrameworkReferences,unresolvedReferences = TcAssemblyResolutions.SplitNonFoundationalResolutions tcConfig
|
|
let tcGlobals,frameworkTcImports = TcImports.BuildFrameworkTcImports (tcConfigP,frameworkDLLs)
|
|
let tcImports = TcImports.BuildNonFrameworkTcImports(tcConfigP,tcGlobals,frameworkTcImports,nonFrameworkReferences)
|
|
tcGlobals,tcImports
|
|
|
|
interface System.IDisposable with
|
|
member tcImports.Dispose() =
|
|
CheckDisposed()
|
|
// disposing deliberately only closes this tcImports, not the ones up the chain
|
|
#if DEBUG
|
|
disposed <- true
|
|
#endif
|
|
if verbose then
|
|
dprintf "disposing of TcImports, %d binaries\n" disposeActions.Length;
|
|
List.iter (fun f -> f()) disposeActions
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Add "#r" and "#I" declarations to the tcConfig
|
|
//--------------------------------------------------------------------------
|
|
|
|
// Add the reference and add the ccu to the type checking environment . Only used by F# Interactive
|
|
let RequireDLL (tcImports:TcImports) tcEnv m file =
|
|
let RequireResolved = function
|
|
| ResolvedImportedAssembly(ccuinfo) -> ccuinfo
|
|
| UnresolvedImportedAssembly(assemblyName) -> error(Error("could not resolve assembly '"^assemblyName^"' required by '"^file,m))
|
|
let resolution = tcImports.ResolveLibFile(AssemblyReference(m,file),ResolveLibFileMode.ReportErrors)
|
|
let dllinfos,ccuinfos = tcImports.RegisterAndImportReferencedAssemblies false [resolution]
|
|
let ccuinfos = ccuinfos |> List.map RequireResolved
|
|
let g = tcImports.GetTcGlobals()
|
|
let amap = tcImports.GetImportMap()
|
|
let tcEnv = ccuinfos |> List.fold (fun tcEnv ccuinfo -> Tc.AddCcuToTcEnv(g,amap,m,tcEnv,ccuinfo.FSharpViewOfMetadata,ccuinfo.AssemblyAutoOpenAttributes,false)) tcEnv
|
|
tcEnv,(dllinfos,ccuinfos)
|
|
|
|
|
|
|
|
let ProcessMetaCommandsFromInput
|
|
(nowarnF: 'state -> range * string -> 'state,
|
|
dllRequireF: 'state -> range * string -> 'state,
|
|
loadSourceF: 'state -> range * string -> unit)
|
|
(tcConfig:TcConfigBuilder)
|
|
inp
|
|
state0 =
|
|
|
|
let canHaveScriptMetaCommands =
|
|
match inp with
|
|
| SigFileInput(_) -> false
|
|
| ImplFileInput(ImplFile(filename,isScript,_,_,_,_,_)) -> isScript
|
|
|
|
let ProcessMetaCommand state hash =
|
|
let mutable matchedm = range0
|
|
try
|
|
match hash with
|
|
| HashDirective("I",args,m) ->
|
|
if not canHaveScriptMetaCommands then
|
|
errorR(HashIncludeNotAllowedInNonScript(m));
|
|
match args with
|
|
| [path] ->
|
|
matchedm<-m
|
|
tcConfig.AddIncludePath(m,path);
|
|
state
|
|
| _ ->
|
|
errorR(Error("Invalid directive. Expected '#I \"<path>\"'",m))
|
|
state
|
|
| HashDirective("nowarn",[d],m) ->
|
|
nowarnF state (m,d)
|
|
| HashDirective(("reference" | "r"),args,m) ->
|
|
if not canHaveScriptMetaCommands then
|
|
errorR(HashReferenceNotAllowedInNonScript(m));
|
|
match args with
|
|
| [path] ->
|
|
matchedm<-m
|
|
dllRequireF state (m,path)
|
|
| _ ->
|
|
errorR(Error("Invalid directive. Expected '#r \"<file-or-assembly>\"'",m))
|
|
state
|
|
| HashDirective(("Reference" | "R"),args,m) ->
|
|
errorR(HashReferenceCopyAfterCompileNotAllowedInNonScript(m));
|
|
match args with
|
|
| [path] ->
|
|
matchedm<-m
|
|
dllRequireF state (m,path)
|
|
| _ -> state
|
|
| HashDirective("load",args,m) ->
|
|
if not canHaveScriptMetaCommands then
|
|
errorR(HashDirectiveNotAllowedInNonScript(m));
|
|
match args with
|
|
| _ :: _ ->
|
|
matchedm<-m
|
|
args |> List.iter (fun path -> loadSourceF state (m,path))
|
|
| _ ->
|
|
errorR(Error("Invalid directive. Expected '#load \"<file>\" ... \"<file>\"'",m))
|
|
state
|
|
| HashDirective("time",args,m) ->
|
|
if not canHaveScriptMetaCommands then
|
|
errorR(HashDirectiveNotAllowedInNonScript(m));
|
|
match args with
|
|
| [] ->
|
|
()
|
|
| ["on" | "off"] ->
|
|
()
|
|
| _ ->
|
|
errorR(Error("Invalid directive. Expected '#time', '#time \"on\"' or '#time \"off\"'",m))
|
|
state
|
|
|
|
| _ ->
|
|
|
|
(* warning(Error("This meta-command has been ignored",m)); *)
|
|
state
|
|
with e -> errorRecovery e matchedm; state
|
|
|
|
let rec WarnOnIgnoredSpecDecls decls =
|
|
decls |> List.iter (fun d ->
|
|
match d with
|
|
| Spec_hash (h,m) -> warning(Error("Directives inside modules are ignored",m));
|
|
| Spec_module (_,subDecls,_) -> WarnOnIgnoredSpecDecls subDecls
|
|
| _ -> ())
|
|
|
|
let rec WarnOnIgnoredImplDecls decls =
|
|
decls |> List.iter (fun d ->
|
|
match d with
|
|
| Def_hash (h,m) -> warning(Error("Directives inside modules are ignored",m));
|
|
| Def_module (_,subDecls,_,_) -> WarnOnIgnoredImplDecls subDecls
|
|
| _ -> ())
|
|
|
|
let ProcessMetaCommandsFromModuleSpec state (ModuleOrNamespaceSpec(_,_,decls,_,_,_,_)) =
|
|
List.fold (fun s d ->
|
|
match d with
|
|
| Spec_hash (h,m) -> ProcessMetaCommand s h
|
|
| Spec_module (_,subDecls,_) -> WarnOnIgnoredSpecDecls subDecls; s
|
|
| _ -> s)
|
|
state
|
|
decls
|
|
|
|
let ProcessMetaCommandsFromModuleImpl state (ModuleOrNamespaceImpl(_,_,decls,_,_,_,_)) =
|
|
List.fold (fun s d ->
|
|
match d with
|
|
| Def_hash (h,m) -> ProcessMetaCommand s h
|
|
| Def_module (_,subDecls,_,_) -> WarnOnIgnoredImplDecls subDecls; s
|
|
| _ -> s)
|
|
state
|
|
decls
|
|
|
|
match inp with
|
|
| SigFileInput(SigFile(_,_,_,hashDirectives,specs)) ->
|
|
let state = List.fold ProcessMetaCommand state0 hashDirectives
|
|
let state = List.fold ProcessMetaCommandsFromModuleSpec state specs
|
|
state
|
|
| ImplFileInput(ImplFile(_,_,_,_,hashDirectives,impls,_)) ->
|
|
let state = List.fold ProcessMetaCommand state0 hashDirectives
|
|
let state = List.fold ProcessMetaCommandsFromModuleImpl state impls
|
|
state
|
|
|
|
let ApplyMetaCommandsFromInputToTcConfig (tcConfig:TcConfig) (inp:input) =
|
|
// Clone
|
|
let tcConfigB = tcConfig.CloneOfOriginalBuilder
|
|
let getWarningNumber = fun () (m,s) -> ()
|
|
let addReferencedAssemblyByPath = fun () (m,s) -> tcConfigB.AddReferencedAssemblyByPath(m,s)
|
|
let addLoadedSource = fun () (m,s) -> tcConfigB.AddLoadedSource(m,s);
|
|
ProcessMetaCommandsFromInput (getWarningNumber, addReferencedAssemblyByPath, addLoadedSource) tcConfigB inp ()
|
|
TcConfig.Create(tcConfigB,validate=false)
|
|
|
|
let GetResolvedAssemblyInformation(tcConfig : TcConfig) : AssemblyResolution list =
|
|
let assemblyList = TcAssemblyResolutions.GetAllDllReferences(tcConfig)
|
|
let resolutions = TcAssemblyResolutions.Resolve(tcConfig,assemblyList)
|
|
resolutions.GetAssemblyResolutions()
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Build the initial type checking environment
|
|
//--------------------------------------------------------------------------
|
|
|
|
let implicitOpen tcGlobals amap m tcEnv p =
|
|
if verbose then dprintf "opening %s\n" p ;
|
|
Tc.TcOpenDecl tcGlobals amap m m tcEnv (path_to_lid m (split_namespace p))
|
|
|
|
let GetInitialTypecheckerEnv (assemblyName:string option) initm (tcConfig:TcConfig) (tcImports:TcImports) tcGlobals =
|
|
let initm = start_range_of_range initm
|
|
if verbose then dprintf "--- building initial tcEnv\n";
|
|
let internalsAreVisibleHere (ccuinfo:ImportedAssembly) =
|
|
match assemblyName with
|
|
| None -> false
|
|
| Some assemblyName ->
|
|
let isTargetAssemblyName (visibleTo:string) =
|
|
try
|
|
System.Reflection.AssemblyName(visibleTo).Name = assemblyName
|
|
with e ->
|
|
warning(InvalidInternalsVisibleToAssemblyName(visibleTo,ccuinfo.FSharpViewOfMetadata.FileName))
|
|
false
|
|
let internalsVisibleTos = ccuinfo.AssemblyInternalsVisibleToAttributes
|
|
List.exists isTargetAssemblyName internalsVisibleTos
|
|
let ccus = tcImports.GetCcuInfos() |> List.map (fun ccuinfo -> ccuinfo.FSharpViewOfMetadata,
|
|
ccuinfo.AssemblyAutoOpenAttributes,
|
|
ccuinfo |> internalsAreVisibleHere)
|
|
let amap = tcImports.GetImportMap()
|
|
let tcEnv = Tc.CreateInitialTcEnv(tcGlobals,amap,initm,ccus) |> (fun tce ->
|
|
if tcConfig.checkOverflow then
|
|
List.fold (implicitOpen tcGlobals amap initm) tce [lib_MFOperatorsChecked_name]
|
|
else
|
|
tce)
|
|
if verbose then dprintf "--- opening implicit paths\n";
|
|
if verbose then dprintf "--- GetInitialTypecheckerEnv, top modules = %s\n" (String.concat ";" (NameMap.domainL (nenv_of_tenv tcEnv).eModulesAndNamespaces));
|
|
if verbose then dprintf "<-- GetInitialTypecheckerEnv\n";
|
|
tcEnv
|
|
|
|
//----------------------------------------------------------------------------
|
|
// TYPECHECK
|
|
//--------------------------------------------------------------------------
|
|
|
|
(* The incremental state of type checking files *)
|
|
(* REVIEW: clean this up *)
|
|
|
|
type topRootedSigs = Zmap.t<QualifiedNameOfFile, ModuleOrNamespaceType>
|
|
type topRootedImpls = QualifiedNameOfFile Zset.t
|
|
type TypecheckerSigsAndImpls = TopSigsAndImpls of topRootedSigs * topRootedImpls * ModuleOrNamespaceType * ModuleOrNamespaceType
|
|
|
|
let qname_ord (q1:QualifiedNameOfFile) (q2:QualifiedNameOfFile) = compare q1.Text q2.Text
|
|
|
|
type tcState =
|
|
{ tcsCcu: ccu;
|
|
tcsCcuType: ModuleOrNamespace;
|
|
tcsNiceNameGen: NiceNameGenerator;
|
|
tcsTcSigEnv: Tc.tcEnv;
|
|
tcsTcImplEnv: Tc.tcEnv;
|
|
(* The accumulated results of type checking for this assembly *)
|
|
tcsTopSigsAndImpls : TypecheckerSigsAndImpls }
|
|
member x.NiceNameGenerator = x.tcsNiceNameGen
|
|
member x.TcEnvFromSignatures = x.tcsTcSigEnv
|
|
member x.TcEnvFromImpls = x.tcsTcImplEnv
|
|
member x.Ccu = x.tcsCcu
|
|
|
|
member x.NextStateAfterIncrementalFragment(tcEnvAtEndOfLastInput) =
|
|
{ x with tcsTcSigEnv = tcEnvAtEndOfLastInput;
|
|
tcsTcImplEnv = tcEnvAtEndOfLastInput }
|
|
|
|
|
|
let TypecheckInitialState(m,ccuName,tcConfig:TcConfig,tcGlobals,niceNameGen,tcEnv0) =
|
|
if verbose then dprintf "Typecheck (constructing initial state)....\n";
|
|
(* Create a ccu to hold all the results of compilation *)
|
|
let ccuType = NewCcuContents ScopeRef_local m ccuName (empty_mtype Namespace)
|
|
let ccu =
|
|
new_ccu ccuName
|
|
{ccu_fsharp=true;
|
|
ccu_usesQuotations=false;
|
|
ccu_filename=None;
|
|
ccu_stamp = new_stamp();
|
|
ccu_qname= None;
|
|
ccu_code_dir = tcConfig.implicitIncludeDir;
|
|
ccu_scoref=ScopeRef_local;
|
|
ccu_contents=ccuType;
|
|
ccu_forwarders=lazy Map.empty }
|
|
|
|
(* OK, is this is the F# library CCU then fix it up. *)
|
|
if tcConfig.compilingFslib then
|
|
tcGlobals.fslibCcu.Fixup(ccu);
|
|
|
|
|
|
{ tcsCcu= ccu;
|
|
tcsCcuType=ccuType;
|
|
tcsNiceNameGen=niceNameGen;
|
|
tcsTcSigEnv=tcEnv0;
|
|
tcsTcImplEnv=tcEnv0;
|
|
tcsTopSigsAndImpls = TopSigsAndImpls (Zmap.empty qname_ord,Zset.empty qname_ord, empty_mtype Namespace, empty_mtype Namespace ) }
|
|
|
|
let CheckSimulateException(tcConfig:TcConfig) =
|
|
match tcConfig.simulateException with
|
|
| Some("tc-oom") -> raise(System.OutOfMemoryException())
|
|
| Some("tc-an") -> raise(System.ArgumentNullException("simulated"))
|
|
| Some("tc-invop") -> raise(System.InvalidOperationException())
|
|
| Some("tc-av") -> raise(System.AccessViolationException())
|
|
| Some("tc-aor") -> raise(System.ArgumentOutOfRangeException())
|
|
| Some("tc-dv0") -> raise(System.DivideByZeroException())
|
|
| Some("tc-nfn") -> raise(System.NotFiniteNumberException())
|
|
| Some("tc-oe") -> raise(System.OverflowException())
|
|
| Some("tc-atmm") -> raise(System.ArrayTypeMismatchException())
|
|
| Some("tc-bif") -> raise(System.BadImageFormatException())
|
|
| Some("tc-knf") -> raise(System.Collections.Generic.KeyNotFoundException())
|
|
| Some("tc-ior") -> raise(System.IndexOutOfRangeException())
|
|
| Some("tc-ic") -> raise(System.InvalidCastException())
|
|
| Some("tc-ip") -> raise(System.InvalidProgramException())
|
|
| Some("tc-ma") -> raise(System.MemberAccessException())
|
|
| Some("tc-ni") -> raise(System.NotImplementedException())
|
|
| Some("tc-nr") -> raise(System.NullReferenceException())
|
|
| Some("tc-oc") -> raise(System.OperationCanceledException())
|
|
| Some("tc-fail") -> failwith "simulated"
|
|
| _ -> ()
|
|
|
|
|
|
(* Typecheck a single file or interactive entry into F# Interactive *)
|
|
let TypecheckOneInputEventually
|
|
checkForNoErrors
|
|
(tcConfig:TcConfig)
|
|
(tcImports:TcImports)
|
|
tcGlobals
|
|
prefixPathOpt
|
|
(tcState:tcState)
|
|
inp =
|
|
eventually {
|
|
try
|
|
CheckSimulateException(tcConfig)
|
|
let (TopSigsAndImpls(topRootedSigs,topRootedImpls,allSigModulTyp,allImplementedSigModulTyp)) = tcState.tcsTopSigsAndImpls
|
|
let m = range_of_input inp
|
|
let amap = tcImports.GetImportMap()
|
|
let! (topAttrs, mimpls,tcEnvAtEnd,tcSigEnv,tcImplEnv,topSigsAndImpls,ccuType) =
|
|
eventually {
|
|
match inp with
|
|
| SigFileInput (SigFile(filename,qualNameOfFile, _,_,_) as file) ->
|
|
(* Check if we've seen this top module signature before. *)
|
|
if Zmap.mem qualNameOfFile topRootedSigs then
|
|
errorR(Error("A signature for the file or module "^qualNameOfFile.Text^" has already been specified",start_range_of_range m));
|
|
|
|
(* Check if the implementation came first in compilation order *)
|
|
if Zset.mem qualNameOfFile topRootedImpls then
|
|
errorR(Error("An implementation of file or module "^qualNameOfFile.Text^" has already been given. Compilation order is significant in F# because of type inference. You may need to adjust the order of your files to place the signature file before the implementation. In Visual Studio files are type-checked in the order they appear in the project file, which can be edited manually or adjusted using the solution explorer",m));
|
|
|
|
(* Typecheck the signature file *)
|
|
if !verboseStamps then
|
|
dprintf "---------------------- START CHECK %A ------------\n" filename;
|
|
let! (tcEnvAtEnd,tcEnv,smodulTypeTopRooted) =
|
|
Tc.TypecheckOneSigFile (tcGlobals,tcState.tcsNiceNameGen,amap,tcState.tcsCcu,checkForNoErrors,tcConfig.conditionalCompilationDefines) tcState.tcsTcSigEnv file
|
|
|
|
if !verboseStamps then
|
|
dprintf "Type-checked signature:\n%s\n" (Layout.showL (Layout.squashTo 192 (EntityTypeL smodulTypeTopRooted)));
|
|
dprintf "---------------------- END CHECK %A ------------\n" filename;
|
|
|
|
let topRootedSigs = Zmap.add qualNameOfFile smodulTypeTopRooted topRootedSigs
|
|
|
|
// Open the prefixPath for fsi.exe
|
|
let tcEnv =
|
|
match prefixPathOpt with
|
|
| None -> tcEnv
|
|
| Some prefixPath ->
|
|
let m = qualNameOfFile.Range
|
|
TcOpenDecl tcGlobals amap m m tcEnv prefixPath
|
|
|
|
(* Build the incremental results *)
|
|
let allSigsModulTyp = combine_mtyps [] m [smodulTypeTopRooted;allSigModulTyp]
|
|
|
|
let ccuType =
|
|
NewCcuContents ScopeRef_local m tcState.tcsCcu.AssemblyName allSigsModulTyp
|
|
|
|
if verbose then dprintf "SigFile, nm = %s, qname = %s\n" (demangled_name_of_modul tcState.tcsCcu.Contents) qualNameOfFile.Text;
|
|
let res = (EmptyTopAttrs, [],tcEnvAtEnd,tcEnv,tcState.tcsTcImplEnv,TopSigsAndImpls(topRootedSigs,topRootedImpls, allSigModulTyp, allImplementedSigModulTyp ),tcState.tcsCcuType)
|
|
return res
|
|
|
|
| ImplFileInput (ImplFile(filename,_,qualNameOfFile,_,_,_,_) as file) ->
|
|
|
|
// Check if we've got an interface for this fragment
|
|
let topRootedSigOpt = topRootedSigs.TryFind(qualNameOfFile)
|
|
|
|
if verbose then dprintf "ImplFileInput, nm = %s, qualNameOfFile = %s, ?topRootedSigOpt = %b\n" filename qualNameOfFile.Text (isSome topRootedSigOpt);
|
|
|
|
// Check if we've already seen an implementation for this fragment
|
|
if Zset.mem qualNameOfFile topRootedImpls then
|
|
errorR(Error("An implementation of the file or module "^qualNameOfFile.Text^" has already been given",m));
|
|
|
|
let tcImplEnv = tcState.tcsTcImplEnv
|
|
|
|
if !verboseStamps then
|
|
dprintf "---------------------- START CHECK %A ------------\n" filename;
|
|
// Typecheck the implementation file
|
|
let! topAttrs,implFile,tcEnvAtEnd =
|
|
Tc.TypecheckOneImplFile (tcGlobals,tcState.tcsNiceNameGen,amap,tcState.tcsCcu,checkForNoErrors,tcConfig.conditionalCompilationDefines) tcImplEnv topRootedSigOpt file
|
|
let hadSig = isSome topRootedSigOpt
|
|
let implFileSigType = SigTypeOfImplFile implFile
|
|
|
|
if !verboseStamps then
|
|
dprintf "Implementation signature:\n%s\n" (Layout.showL (Layout.squashTo 192 (EntityTypeL implFileSigType)));
|
|
dprintf "---------------------- END CHECK %A ------------\n" filename;
|
|
|
|
if verbose then dprintf "done TypecheckOneImplFile...\n";
|
|
let topRootedImpls = Zset.add qualNameOfFile topRootedImpls
|
|
|
|
// Only add it to the environment if it didn't have a signature
|
|
let m = qualNameOfFile.Range
|
|
let tcImplEnv = Tc.AddLocalTopRootedModuleOrNamespace tcGlobals amap m tcImplEnv implFileSigType
|
|
let tcSigEnv =
|
|
if hadSig then tcState.tcsTcSigEnv
|
|
else Tc.AddLocalTopRootedModuleOrNamespace tcGlobals amap m tcState.tcsTcSigEnv implFileSigType
|
|
|
|
// Open the prefixPath for fsi.exe
|
|
let tcImplEnv =
|
|
match prefixPathOpt with
|
|
| None -> tcImplEnv
|
|
| Some prefixPath ->
|
|
TcOpenDecl tcGlobals amap m m tcImplEnv prefixPath
|
|
|
|
let allImplementedSigModulTyp = combine_mtyps [] m [implFileSigType; allImplementedSigModulTyp]
|
|
|
|
// Add it to the CCU
|
|
let ccuType =
|
|
// The signature must be reestablished.
|
|
// [CHECK: Why? This seriously degraded performance]
|
|
NewCcuContents ScopeRef_local m tcState.tcsCcu.AssemblyName allImplementedSigModulTyp
|
|
|
|
if verbose then dprintf "done TypecheckOneInputEventually...\n";
|
|
|
|
let topSigsAndImpls = TopSigsAndImpls(topRootedSigs,topRootedImpls,allSigModulTyp,allImplementedSigModulTyp)
|
|
let res = (topAttrs,[implFile], tcEnvAtEnd, tcSigEnv, tcImplEnv,topSigsAndImpls,ccuType)
|
|
return res }
|
|
|
|
return (tcEnvAtEnd,topAttrs,mimpls),
|
|
{ tcState with
|
|
tcsCcuType=ccuType;
|
|
tcsTcSigEnv=tcSigEnv;
|
|
tcsTcImplEnv=tcImplEnv;
|
|
tcsTopSigsAndImpls = topSigsAndImpls }
|
|
with e ->
|
|
errorRecovery e range0;
|
|
return (tcState.TcEnvFromSignatures,EmptyTopAttrs,[]),tcState
|
|
}
|
|
|
|
let TypecheckOneInput checkForNoErrors tcConfig tcImports tcGlobals prefixPathOpt tcState inp =
|
|
// 'use' ensures that the warning handler is restored at the end
|
|
use unwind = InstallGlobalErrorLogger(fun oldLogger -> GetErrorLoggerFilteringByScopedPragmas(false,GetScopedPragmasForInput(inp),oldLogger))
|
|
TypecheckOneInputEventually checkForNoErrors tcConfig tcImports tcGlobals prefixPathOpt tcState inp |> Eventually.force
|
|
|
|
let TypecheckMultipleInputsFinish(results,tcState:tcState) =
|
|
let tcEnvsAtEndFile,topAttrs,mimpls = List.unzip3 results
|
|
|
|
let topAttrs = List.foldBack CombineTopAttrs topAttrs EmptyTopAttrs
|
|
let mimpls = List.concat mimpls
|
|
// This is the environment required by fsi.exe when incrementally adding definitions
|
|
let tcEnvAtEndOfLastFile = (match tcEnvsAtEndFile with h :: _ -> h | _ -> tcState.TcEnvFromSignatures)
|
|
if verbose then dprintf "done TypecheckMultipleInputs...\n";
|
|
|
|
(tcEnvAtEndOfLastFile,topAttrs,mimpls),tcState
|
|
|
|
let TypecheckMultipleInputs(checkForNoErrors,tcConfig:TcConfig,tcImports,tcGlobals,prefixPathOpt,tcState,inputs) =
|
|
let results,tcState = List.mapfold (TypecheckOneInput checkForNoErrors tcConfig tcImports tcGlobals prefixPathOpt) tcState inputs
|
|
TypecheckMultipleInputsFinish(results,tcState)
|
|
|
|
let TypecheckClosedInputSetFinish(mimpls,tcState) =
|
|
// Publish the latest contents to the CCU
|
|
tcState.tcsCcu.Deref.ccu_contents <- tcState.tcsCcuType;
|
|
|
|
// Check all interfaces have implementations
|
|
let (TopSigsAndImpls(topRootedSigs,topRootedImpls,_,_)) = tcState.tcsTopSigsAndImpls
|
|
topRootedSigs |> Zmap.iter (fun qualNameOfFile y ->
|
|
if not (Zset.mem qualNameOfFile topRootedImpls) then
|
|
errorR(Error("The signature file "^qualNameOfFile.Text^" does not have a corresponding implementation file. If an implementation file exists then check the 'module' and 'namespace' declarations in the signature and implementation files match", qualNameOfFile.Range)));
|
|
if verbose then dprintf "done TypecheckClosedInputSet...\n";
|
|
let tassembly = TAssembly(mimpls)
|
|
tcState, tassembly
|
|
|
|
let TypecheckClosedInputSet(checkForNoErrors,tcConfig,tcImports,tcGlobals,prefixPathOpt,tcState,inputs) =
|
|
// tcEnvAtEndOfLastFile is the environment required by fsi.exe when incrementally adding definitions
|
|
let (tcEnvAtEndOfLastFile,topAttrs,mimpls),tcState = TypecheckMultipleInputs (checkForNoErrors,tcConfig,tcImports,tcGlobals,prefixPathOpt,tcState,inputs)
|
|
let tcState,tassembly = TypecheckClosedInputSetFinish (mimpls, tcState)
|
|
tcState, topAttrs, tassembly, tcEnvAtEndOfLastFile
|
|
|
|
type OptionSwitch =
|
|
| On
|
|
| Off
|
|
|
|
type OptionSpec =
|
|
| OptionClear of bool ref
|
|
| OptionFloat of (float -> unit)
|
|
| OptionInt of (int -> unit)
|
|
| OptionSwitch of (OptionSwitch -> unit)
|
|
| OptionIntList of (int -> unit)
|
|
| OptionIntListSwitch of (int -> OptionSwitch -> unit)
|
|
| OptionRest of (string -> unit)
|
|
| OptionSet of bool ref
|
|
| OptionString of (string -> unit)
|
|
| OptionStringList of (string -> unit)
|
|
| OptionStringListSwitch of (string -> OptionSwitch -> unit)
|
|
| OptionUnit of (unit -> unit)
|
|
| OptionHelp of (CompilerOptionBlock list -> unit) // like OptionUnit, but given the "options"
|
|
| OptionGeneral of (string list -> bool) * (string list -> string list) // Applies? * (ApplyReturningResidualArgs)
|
|
|
|
and CompilerOption = CompilerOption of string * string * OptionSpec * Option<exn> * string list
|
|
and CompilerOptionBlock = PublicOptions of string * CompilerOption list | PrivateOptions of CompilerOption list
|
|
let blockOptions = function PublicOptions (heading,opts) -> opts | PrivateOptions opts -> opts
|
|
|
|
let filterCompilerOptionBlock pred block =
|
|
match block with
|
|
| PublicOptions(heading,opts) -> PublicOptions(heading,List.filter pred opts)
|
|
| PrivateOptions(opts) -> PrivateOptions(List.filter pred opts)
|
|
|
|
let compilerOptionUsage (CompilerOption(s,tag,spec,_,help)) =
|
|
let s = if s="--" then "" else s (* s="flag" for "--flag" options. s="--" for "--" option. Adjust printing here for "--" case. *)
|
|
match spec with
|
|
| (OptionUnit _ | OptionSet _ | OptionClear _ | OptionHelp _) -> sprintf "--%s" s
|
|
| OptionStringList f -> sprintf "--%s:%s" s tag
|
|
| OptionIntList f -> sprintf "--%s:%s" s tag
|
|
| OptionSwitch f -> sprintf "--%s[+|-]" s
|
|
| OptionStringListSwitch f -> sprintf "--%s[+|-]:%s" s tag
|
|
| OptionIntListSwitch f -> sprintf "--%s[+|-]:%s" s tag
|
|
| OptionString f -> sprintf "--%s:%s" s tag
|
|
| OptionInt f -> sprintf "--%s:%s" s tag
|
|
| OptionFloat f -> sprintf "--%s:%s" s tag
|
|
| OptionRest f -> sprintf "--%s ..." s
|
|
| OptionGeneral (pred,exec) -> if tag="" then sprintf "%s" s else sprintf "%s:%s" s tag (* still being decided *)
|
|
|
|
let printCompilerOption (CompilerOption(s,tag,spec,_,help) as compilerOption) =
|
|
let flagWidth = 30 // fixed width for printing of flags, e.g. --warnaserror:<warn;...>
|
|
let lineWidth = try System.Console.BufferWidth with e -> 80
|
|
// Lines have this form: <flagWidth><space><description>
|
|
// flagWidth chars - for flags description or padding on continuation lines.
|
|
// single space - space.
|
|
// description - words upto but excluding the final character of the line.
|
|
assert(flagWidth = 30)
|
|
printf "%-30s" (compilerOptionUsage compilerOption)
|
|
let printWord column (word:string) =
|
|
// Have printed upto column.
|
|
// Now print the next word including any preceeding whitespace.
|
|
// Returns the column printed to (suited to folding).
|
|
if column + 1 (*space*) + word.Length >= lineWidth then // NOTE: "equality" ensures final character of the line is never printed
|
|
printfn "" (* newline *)
|
|
assert(flagWidth = 30)
|
|
printf "%-30s %s" ""(*<--flags*) word
|
|
flagWidth + 1 + word.Length
|
|
else
|
|
printf " %s" word
|
|
column + 1 + word.Length
|
|
let words = (String.concat " " help).Split [| ' ' |]
|
|
let finalColumn = Array.fold printWord flagWidth words
|
|
printfn "" (* newline *)
|
|
|
|
let printPublicOptions (heading,opts) =
|
|
if opts<>[] then
|
|
printfn ""
|
|
printfn ""
|
|
printfn "\t\t%s" heading
|
|
List.iter printCompilerOption opts
|
|
|
|
let printCompilerOptionBlocks blocks =
|
|
let equals x y = x=y
|
|
let publicBlocks = List.choose (function PrivateOptions _ -> None | PublicOptions (heading,opts) -> Some (heading,opts)) blocks
|
|
let consider doneHeadings (heading,opts) =
|
|
if Set.mem heading doneHeadings then
|
|
doneHeadings
|
|
else
|
|
let headingOptions = List.filter (fst >> equals heading) publicBlocks |> List.map snd |> List.concat
|
|
printPublicOptions (heading,headingOptions)
|
|
Set.add heading doneHeadings
|
|
List.fold consider Set.empty publicBlocks |> ignore<Set<string>>
|
|
|
|
(* For QA *)
|
|
let dumpCompilerOption prefix (CompilerOption(str,tag,spec,_,help)) =
|
|
printf "section='%-25s' ! option=%-30s kind=" prefix str
|
|
match spec with
|
|
| OptionUnit _ -> printf "OptionUnit"
|
|
| OptionSet _ -> printf "OptionSet"
|
|
| OptionClear _ -> printf "OptionClear"
|
|
| OptionHelp _ -> printf "OptionHelp"
|
|
| OptionStringList _ -> printf "OptionStringList"
|
|
| OptionIntList _ -> printf "OptionIntList"
|
|
| OptionSwitch _ -> printf "OptionSwitch"
|
|
| OptionStringListSwitch _ -> printf "OptionStringListSwitch"
|
|
| OptionIntListSwitch _ -> printf "OptionIntListSwitch"
|
|
| OptionString _ -> printf "OptionString"
|
|
| OptionInt _ -> printf "OptionInt"
|
|
| OptionFloat _ -> printf "OptionFloat"
|
|
| OptionRest _ -> printf "OptionRest"
|
|
| OptionGeneral _ -> printf "OptionGeneral"
|
|
printf "\n"
|
|
let dumpCompilerOptionBlock = function
|
|
| PublicOptions (heading,opts) -> List.iter (dumpCompilerOption heading) opts
|
|
| PrivateOptions opts -> List.iter (dumpCompilerOption "NoSection") opts
|
|
let dumpCompilerOptionBlocks blocks = List.iter dumpCompilerOptionBlock blocks
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
// The argument parser is used by both the VS plug-in and the fsc.exe to
|
|
// parse the include file path and other front-end arguments.
|
|
//
|
|
// The language service uses this function too. It's important to continue
|
|
// processing flags even if an error is seen in one so that the best possible
|
|
// intellisense can be show.
|
|
//--------------------------------------------------------------------------
|
|
let ParseCompilerOptions (collectOtherArgument : string -> unit) (blocks: CompilerOptionBlock list) args =
|
|
let specs : CompilerOption list = List.collect blockOptions blocks
|
|
|
|
// returns a tuple - the option token, the option argument string
|
|
let parseOption (s : string) =
|
|
// grab the option token
|
|
let opts = s.Split([|':'|])
|
|
let mutable opt = opts.[0]
|
|
// if it doesn't start with a '-' or '/', reject outright
|
|
if opt.[0] <> '-' && opt.[0] <> '/' then
|
|
opt <- ""
|
|
elif opt <> "--" then
|
|
// is it an abbreviated or MSFT-style option?
|
|
// if so, strip the first character and move on with your life
|
|
if opt.Length = 2 || opt.[0] = '/' then
|
|
opt <- opt.[1 ..]
|
|
// else, it should be a non-abbreviated option starting with "--"
|
|
elif opt.Length > 3 && opt.StartsWith("--") then
|
|
opt <- opt.[2 ..]
|
|
else
|
|
opt <- ""
|
|
(*
|
|
// is it two characters? If so, strip '-' or '/' from the start
|
|
if opt <> "--" && opt.Length > 1 && (opt.[0] = '-' || opt.[0] = '/') then
|
|
opt <- opt.[1 ..]
|
|
// is it more than two characters? If so, strip "--" or '/' from the start
|
|
if opt.Length > 2 && opt.[0] = '-' then // abbreviated options should have only 1 '-'
|
|
opt <- opt.[1 ..]
|
|
*)
|
|
// get the argument string
|
|
let optArgs = if opts.Length > 1 then String.Join(":",opts.[1 ..]) else ""
|
|
opt, optArgs
|
|
|
|
let getOptionArg compilerOption (argString : string) =
|
|
if argString = "" then
|
|
let es = sprintf "option requires parameter: %s" (compilerOptionUsage compilerOption)
|
|
errorR(Error(es,rangeCmdArgs)) ;
|
|
argString
|
|
|
|
let getOptionArgList compilerOption (argString : string) =
|
|
if argString = "" then
|
|
let es = sprintf "option requires parameter: %s" (compilerOptionUsage compilerOption)
|
|
errorR(Error(es,rangeCmdArgs)) ;
|
|
[]
|
|
else
|
|
argString.Split([|',';';'|]) |> List.of_array
|
|
|
|
let getSwitchOpt (opt : string) =
|
|
// if opt is a switch, strip the '+' or '-'
|
|
if opt <> "--" && opt.Length > 1 && (opt.EndsWith("+",StringComparison.Ordinal) || opt.EndsWith("-",StringComparison.Ordinal)) then
|
|
opt.[0 .. opt.Length - 2]
|
|
else
|
|
opt
|
|
|
|
let getSwitch (s: string) =
|
|
let s = (s.Split([|':'|])).[0]
|
|
if s <> "--" && s.EndsWith("-",StringComparison.Ordinal) then Off else On
|
|
|
|
let rec process_arg args =
|
|
match args with
|
|
| [] -> ()
|
|
| opt :: t ->
|
|
|
|
let optToken, argString = parseOption opt
|
|
|
|
let report_deprecated_option deprecated =
|
|
match deprecated with
|
|
| Some(e) -> warning(e)
|
|
| None -> ()
|
|
|
|
let rec attempt l =
|
|
match l with
|
|
| (CompilerOption(s, _, OptionHelp f, d, _) :: _) when optToken = s && argString = "" ->
|
|
report_deprecated_option d
|
|
f blocks; t
|
|
| (CompilerOption(s, _, OptionUnit f, d, _) :: _) when optToken = s && argString = "" ->
|
|
report_deprecated_option d
|
|
f (); t
|
|
| (CompilerOption(s, _, OptionSwitch f, d, _) :: _) when getSwitchOpt(optToken) = s && argString = "" ->
|
|
report_deprecated_option d
|
|
f (getSwitch opt); t
|
|
| (CompilerOption(s, _, OptionSet f, d, _) :: _) when optToken = s && argString = "" ->
|
|
report_deprecated_option d
|
|
f := true; t
|
|
| (CompilerOption(s, _, OptionClear f, d, _) :: _) when optToken = s && argString = "" ->
|
|
report_deprecated_option d
|
|
f := false; t
|
|
| (CompilerOption(s, _, OptionString f, d, _) as compilerOption :: _) when optToken = s ->
|
|
report_deprecated_option d
|
|
let oa = getOptionArg compilerOption argString
|
|
if oa <> "" then
|
|
f (getOptionArg compilerOption oa)
|
|
t
|
|
| (CompilerOption(s, _, OptionInt f, d, _) as compilerOption :: _) when optToken = s ->
|
|
report_deprecated_option d
|
|
let oa = getOptionArg compilerOption argString
|
|
if oa <> "" then
|
|
f (try int32 (oa) with _ ->
|
|
errorR(Error("'"^(getOptionArg compilerOption argString)^"' is not a valid integer argument",rangeCmdArgs)); 0)
|
|
t
|
|
| (CompilerOption(s, _, OptionFloat f, d, _) as compilerOption :: _) when optToken = s ->
|
|
report_deprecated_option d
|
|
let oa = getOptionArg compilerOption argString
|
|
if oa <> "" then
|
|
f (try float (oa) with _ ->
|
|
errorR(Error(("'"^getOptionArg compilerOption argString)^"' is not a valid floating point argument", rangeCmdArgs)); 0.0)
|
|
t
|
|
| (CompilerOption(s, _, OptionRest f, d, _) :: _) when optToken = s ->
|
|
report_deprecated_option d
|
|
List.iter f t; []
|
|
| (CompilerOption(s, _, OptionIntList f, d, _) as compilerOption :: _) when optToken = s ->
|
|
report_deprecated_option d
|
|
let al = getOptionArgList compilerOption argString
|
|
if al <> [] then
|
|
List.iter (fun i -> f (try int32 i with _ -> errorR(Error(("'"^i^"' is not a valid integer argument"),rangeCmdArgs)); 0)) al ;
|
|
t
|
|
| (CompilerOption(s, _, OptionIntListSwitch f, d, _) as compilerOption :: _) when getSwitchOpt(optToken) = s ->
|
|
report_deprecated_option d
|
|
let al = getOptionArgList compilerOption argString
|
|
if al <> [] then
|
|
let switch = getSwitch(opt)
|
|
List.iter (fun i -> f (try int32 i with _ -> errorR(Error(("'"^i^"' is not a valid integer argument"),rangeCmdArgs)); 0) switch) al ;
|
|
t
|
|
// here
|
|
| (CompilerOption(s, _, OptionStringList f, d, _) as compilerOption :: _) when optToken = s ->
|
|
report_deprecated_option d
|
|
let al = getOptionArgList compilerOption argString
|
|
if al <> [] then
|
|
List.iter (fun s -> f s) (getOptionArgList compilerOption argString)
|
|
t
|
|
| (CompilerOption(s, _, OptionStringListSwitch f, d, _) as compilerOption :: _) when getSwitchOpt(optToken) = s ->
|
|
report_deprecated_option d
|
|
let al = getOptionArgList compilerOption argString
|
|
if al <> [] then
|
|
let switch = getSwitch(opt)
|
|
List.iter (fun s -> f s switch) (getOptionArgList compilerOption argString)
|
|
t
|
|
| (CompilerOption(s, _, OptionGeneral (pred,exec), d, _) :: more) when pred args ->
|
|
report_deprecated_option d
|
|
let rest = exec args in rest // arguments taken, rest remaining
|
|
| (_ :: more) -> attempt more
|
|
| [] ->
|
|
if (opt.[0] = '-' || opt.[0] = '/') then
|
|
// want the whole opt token - delimeter and all
|
|
let unrecOpt = sprintf "'%s'" (opt.Split([|':'|]).[0])
|
|
errorR(Error("unrecognized option: "^ unrecOpt,rangeCmdArgs)) ;
|
|
t
|
|
else
|
|
(collectOtherArgument opt; t)
|
|
let rest = attempt specs
|
|
process_arg rest
|
|
|
|
let result = process_arg args
|
|
result
|
|
|