From 74369e8d06b4df88e53577ede0f633a64455acfb Mon Sep 17 00:00:00 2001 From: Adam Boniecki Date: Wed, 28 Jun 2023 18:37:49 +0200 Subject: [PATCH 1/7] Add unit test --- .../Types/RecordTypes/AnonymousRecords.fs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs index e9dbe8ffd43..12ec08fb10a 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/AnonymousRecords.fs @@ -64,4 +64,14 @@ type ErrorResponse = Error 10, Line 5, Col 42, Line 5, Col 43, "Unexpected integer literal in field declaration. Expected ':' or other token." Error 10, Line 7, Col 12, Line 7, Col 14, "Unexpected symbol '|}' in field declaration. Expected identifier or other token." Error 10, Line 10, Col 17, Line 10, Col 21, "Incomplete structured construct at or before this point in field declaration. Expected identifier or other token." - ] \ No newline at end of file + ] + + [] + let ``Nested anonymous records where outer label = concatenated inner labels (see secondary issue reported in 6411)`` () = + FSharp """ +module NestedAnonRecds + +let x = {| abcd = {| ab = 4; cd = 1 |} |} +""" + |> compile + |> shouldSucceed \ No newline at end of file From e141749ecea44d18f2e7721746aa40602b041396 Mon Sep 17 00:00:00 2001 From: Adam Boniecki Date: Wed, 28 Jun 2023 19:15:09 +0200 Subject: [PATCH 2/7] Fix AnonRecdTypeInfo creation Add a separator in between labels' bytes to prevent later hash collision --- src/Compiler/TypedTree/TypedTree.fs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index b18cdd1d2a9..07e872f00a4 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -4280,7 +4280,8 @@ type AnonRecdTypeInfo = match tupInfo with | TupInfo.Const b -> yield (if b then 0uy else 1uy) for id in sortedIds do - for c in id.idText do yield byte c; yield byte (int32 c >>> 8) |] + for c in id.idText do yield byte c; yield byte (int32 c >>> 8) + yield 0uy |] let sortedNames = Array.map textOfId sortedIds { Assembly = ccu; TupInfo = tupInfo; SortedIds = sortedIds; Stamp = stamp; SortedNames = sortedNames } From 397505873d8f4d6f83350f55c9013fbbabcb9084 Mon Sep 17 00:00:00 2001 From: Adam Boniecki Date: Mon, 3 Jul 2023 15:34:02 +0200 Subject: [PATCH 3/7] Separate stamp and key used in postinference check --- src/Compiler/TypedTree/TypedTree.fs | 22 +++++++++++++++++----- src/Compiler/TypedTree/TypedTree.fsi | 3 ++- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index 07e872f00a4..bad04d71c0f 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -4268,22 +4268,33 @@ type AnonRecdTypeInfo = mutable Stamp: Stamp mutable SortedNames: string[] + + mutable IlTypeName : int64 } /// Create an AnonRecdTypeInfo from the basic data static member Create(ccu: CcuThunk, tupInfo, ids: Ident[]) = let sortedIds = ids |> Array.sortBy (fun id -> id.idText) // Hash all the data to form a unique stamp - let stamp = - sha1HashInt64 + let stamp = + sha1HashInt64 [| for c in ccu.AssemblyName do yield byte c; yield byte (int32 c >>> 8) match tupInfo with | TupInfo.Const b -> yield (if b then 0uy else 1uy) for id in sortedIds do for c in id.idText do yield byte c; yield byte (int32 c >>> 8) yield 0uy |] + + let ilName = + sha1HashInt64 + [| for c in ccu.AssemblyName do yield byte c; yield byte (int32 c >>> 8) + match tupInfo with + | TupInfo.Const b -> yield (if b then 0uy else 1uy) + for id in sortedIds do + for c in id.idText do yield byte c; yield byte (int32 c >>> 8) |] + let sortedNames = Array.map textOfId sortedIds - { Assembly = ccu; TupInfo = tupInfo; SortedIds = sortedIds; Stamp = stamp; SortedNames = sortedNames } + { Assembly = ccu; TupInfo = tupInfo; SortedIds = sortedIds; Stamp = stamp; SortedNames = sortedNames; IlTypeName = ilName } /// Get the ILTypeRef for the generated type implied by the anonymous type member x.ILTypeRef = @@ -4294,8 +4305,9 @@ type AnonRecdTypeInfo = { Assembly = Unchecked.defaultof<_> TupInfo = Unchecked.defaultof<_> SortedIds = Unchecked.defaultof<_> - Stamp = Unchecked.defaultof<_> - SortedNames = Unchecked.defaultof<_> } + Stamp = Unchecked.defaultof<_> + SortedNames = Unchecked.defaultof<_> + IlTypeName = Unchecked.defaultof<_> } member x.Link d = let sortedNames = Array.map textOfId d.SortedIds diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi index bcc951ecc4d..966c97a7f2b 100644 --- a/src/Compiler/TypedTree/TypedTree.fsi +++ b/src/Compiler/TypedTree/TypedTree.fsi @@ -3064,7 +3064,8 @@ type AnonRecdTypeInfo = mutable TupInfo: TupInfo mutable SortedIds: Syntax.Ident[] mutable Stamp: Stamp - mutable SortedNames: string[] } + mutable SortedNames: string[] + mutable IlTypeName: int64 } /// Create an AnonRecdTypeInfo from the basic data static member Create: ccu: CcuThunk * tupInfo: TupInfo * ids: Syntax.Ident[] -> AnonRecdTypeInfo From 2788ed29091c545e6b9956451d8581bbefc67048 Mon Sep 17 00:00:00 2001 From: Adam Boniecki Date: Fri, 30 Jun 2023 12:30:15 +0200 Subject: [PATCH 4/7] Remove some whitespace --- src/Compiler/Checking/PostInferenceChecks.fs | 1196 +++++++++--------- 1 file changed, 598 insertions(+), 598 deletions(-) diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index 145c7e0799c..b9dd8dbcc14 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -32,24 +32,24 @@ open FSharp.Compiler.TypeRelations //-------------------------------------------------------------------------- // NOTES: reraise safety checks //-------------------------------------------------------------------------- - + // "rethrow may only occur with-in the body of a catch handler". // -- Section 4.23. Part III. CLI Instruction Set. ECMA Draft 2002. -// +// // 1. reraise() calls are converted to TOp.Reraise in the type checker. // 2. any remaining reraise val_refs will be first class uses. These are trapped. // 3. The freevars track free TOp.Reraise (they are bound (cleared) at try-catch handlers). // 4. An outermost expression is not contained in a try-catch handler. -// These may not have unbound rethrows. +// These may not have unbound rethrows. // Outermost expressions occur at: // * module bindings. // * attribute arguments. -// * Any more? What about fields of a static class? +// * Any more? What about fields of a static class? // 5. A lambda body (from lambda-expression or method binding) will not occur under a try-catch handler. // These may not have unbound rethrows. // 6. All other constructs are assumed to generate IL code sequences. // For correctness, this claim needs to be justified. -// +// // Informal justification: // If a reraise occurs, then it is minimally contained by either: // a) a try-catch - accepted. @@ -67,15 +67,15 @@ type Resumable = | None /// Indicates we are expecting resumable code (the body of a ResumableCode delegate or /// the body of the MoveNextMethod for a state machine) - /// -- allowed: are we inside the 'then' branch of an 'if __useResumableCode then ...' + /// -- allowed: are we inside the 'then' branch of an 'if __useResumableCode then ...' /// for a ResumableCode delegate. | ResumableExpr of allowed: bool -type env = - { +type env = + { /// The bound type parameter names in scope - boundTyparNames: string list - + boundTyparNames: string list + /// The bound type parameters in scope boundTypars: TyparMap @@ -83,45 +83,45 @@ type env = argVals: ValMap /// "module remap info", i.e. hiding information down the signature chain, used to compute what's hidden by a signature - sigToImplRemapInfo: (Remap * SignatureHidingInfo) list + sigToImplRemapInfo: (Remap * SignatureHidingInfo) list /// Are we in a quotation? - quote : bool + quote : bool /// Are we under []? reflect : bool /// Are we in an extern declaration? - external : bool - + external : bool + /// Current return scope of the expr. - returnScope : int - + returnScope : int + /// Are we in an app expression (Expr.App)? isInAppExpr: bool /// Are we expecting a resumable code block etc resumableCode: Resumable - } + } override _.ToString() = "" -let BindTypar env (tp: Typar) = - { env with +let BindTypar env (tp: Typar) = + { env with boundTyparNames = tp.Name :: env.boundTyparNames - boundTypars = env.boundTypars.Add (tp, ()) } + boundTypars = env.boundTypars.Add (tp, ()) } -let BindTypars g env (tps: Typar list) = +let BindTypars g env (tps: Typar list) = let tps = NormalizeDeclaredTyparsForEquiRecursiveInference g tps if isNil tps then env else - // Here we mutate to provide better names for generalized type parameters + // Here we mutate to provide better names for generalized type parameters let nms = PrettyTypes.PrettyTyparNames (fun _ -> true) env.boundTyparNames tps - PrettyTypes.AssignPrettyTyparNames tps nms - List.fold BindTypar env tps + PrettyTypes.AssignPrettyTyparNames tps nms + List.fold BindTypar env tps -/// Set the set of vals which are arguments in the active lambda. We are allowed to return +/// Set the set of vals which are arguments in the active lambda. We are allowed to return /// byref arguments as byref returns. -let BindArgVals env (vs: Val list) = +let BindArgVals env (vs: Val list) = { env with argVals = ValMap.OfList (List.map (fun v -> (v, ())) vs) } /// Limit flags represent a type(s) returned from checking an expression(s) that is interesting to impose rules on. @@ -152,7 +152,7 @@ let NoLimit = { scope = 0; flags = LimitFlags.None } // Combining two limits will result in both limit flags merged. // If none of the limits are limited by a by-ref or a stack referring span-like // the scope will be 0. -let CombineTwoLimits limit1 limit2 = +let CombineTwoLimits limit1 limit2 = let isByRef1 = HasLimitFlag LimitFlags.ByRef limit1 let isByRef2 = HasLimitFlag LimitFlags.ByRef limit2 let isStackSpan1 = HasLimitFlag LimitFlags.StackReferringSpanLike limit1 @@ -160,7 +160,7 @@ let CombineTwoLimits limit1 limit2 = let isLimited1 = isByRef1 || isStackSpan1 let isLimited2 = isByRef2 || isStackSpan2 - // A limit that has a stack referring span-like but not a by-ref, + // A limit that has a stack referring span-like but not a by-ref, // we force the scope to 1. This is to handle call sites // that return a by-ref and have stack referring span-likes as arguments. // This is to ensure we can only prevent out of scope at the method level rather than visibility. @@ -190,27 +190,27 @@ let CombineLimits limits = (NoLimit, limits) ||> List.fold CombineTwoLimits -type cenv = +type cenv = { boundVals: Dictionary // really a hash set limitVals: Dictionary - mutable potentialUnboundUsesOfVals: StampMap + mutable potentialUnboundUsesOfVals: StampMap - mutable anonRecdTypes: StampMap + mutable anonRecdTypes: StampMap stackGuard: StackGuard - g: TcGlobals + g: TcGlobals - amap: Import.ImportMap + amap: Import.ImportMap /// For reading metadata infoReader: InfoReader internalsVisibleToPaths : CompilationPath list - denv: DisplayEnv + denv: DisplayEnv viewCcu : CcuThunk @@ -223,8 +223,8 @@ type cenv = // outputs mutable usesQuotations: bool - mutable entryPointGiven: bool - + mutable entryPointGiven: bool + /// Callback required for quotation generation tcVal: ConstraintSolver.TcValF } @@ -261,7 +261,7 @@ let GetLimitVal cenv env m (v: Val) = elif isByrefTy cenv.g v.Type then let isByRefOfSpanLike = isSpanLikeTy cenv.g m (destByrefTy cenv.g v.Type) - + if isByRefOfSpanLike then if HasLimitFlag LimitFlags.ByRefOfStackReferringSpanLike limit then { limit with flags = LimitFlags.ByRefOfStackReferringSpanLike } @@ -292,15 +292,15 @@ let GetLimitValByRef cenv env m v = { scope = scope; flags = flags } -let LimitVal cenv (v: Val) limit = +let LimitVal cenv (v: Val) limit = if not v.IgnoresByrefScope then cenv.limitVals[v.Stamp] <- limit -let BindVal cenv env (v: Val) = +let BindVal cenv env (v: Val) = //printfn "binding %s..." v.DisplayName let alreadyDone = cenv.boundVals.ContainsKey v.Stamp cenv.boundVals[v.Stamp] <- 1 - + let topLevelBindingHiddenBySignatureFile () = let parentHasSignatureFile () = match v.TryDeclaringEntity with @@ -311,14 +311,14 @@ let BindVal cenv env (v: Val) = | ValueSome e -> e.HasSignatureFile v.IsModuleBinding && not v.HasSignatureFile && parentHasSignatureFile () - + if not env.external && not alreadyDone && - cenv.reportErrors && - not v.HasBeenReferenced && + cenv.reportErrors && + not v.HasBeenReferenced && (not v.IsCompiledAsTopLevel || topLevelBindingHiddenBySignatureFile ()) && not (v.DisplayName.StartsWithOrdinal("_")) && - not v.IsCompilerGenerated then + not v.IsCompilerGenerated then if v.IsCtorThisVal then warning (Error(FSComp.SR.chkUnusedThisVariable v.DisplayName, v.Range)) @@ -328,7 +328,7 @@ let BindVal cenv env (v: Val) = let BindVals cenv env vs = List.iter (BindVal cenv env) vs let RecordAnonRecdInfo cenv (anonInfo: AnonRecdTypeInfo) = - if not (cenv.anonRecdTypes.ContainsKey anonInfo.Stamp) then + if not (cenv.anonRecdTypes.ContainsKey anonInfo.Stamp) then cenv.anonRecdTypes <- cenv.anonRecdTypes.Add(anonInfo.Stamp, anonInfo) //-------------------------------------------------------------------------- @@ -341,40 +341,40 @@ let rec CheckTypeDeep (cenv: cenv) (visitTy, visitTyconRefOpt, visitAppTyOpt, vi // those attached to _solved_ type variables. This is used by PostTypeCheckSemanticChecks to detect uses of // values as solutions to trait constraints and determine if inference has caused the value to escape its scope. // The only record of these solutions is in the _solved_ constraints of types. - // In an ideal world we would, instead, record the solutions to these constraints as "witness variables" in expressions, - // rather than solely in types. - match ty with + // In an ideal world we would, instead, record the solutions to these constraints as "witness variables" in expressions, + // rather than solely in types. + match ty with | TType_var (tp, _) when tp.Solution.IsSome -> for cx in tp.Constraints do - match cx with - | TyparConstraint.MayResolveMember(TTrait(_, _, _, _, _, soln), _) -> - match visitTraitSolutionOpt, soln.Value with + match cx with + | TyparConstraint.MayResolveMember(TTrait(_, _, _, _, _, soln), _) -> + match visitTraitSolutionOpt, soln.Value with | Some visitTraitSolution, Some sln -> visitTraitSolution sln | _ -> () | _ -> () | _ -> () - + let ty = if g.compilingFSharpCore then match stripTyparEqns ty with // When compiling FSharp.Core, do not strip type equations at this point if we can't dereference a tycon. | TType_app (tcref, _, _) when not tcref.CanDeref -> ty | _ -> stripTyEqns g ty - else + else stripTyEqns g ty visitTy ty match ty with - | TType_forall (tps, body) -> + | TType_forall (tps, body) -> let env = BindTypars g env tps - CheckTypeDeep cenv f g env isInner body + CheckTypeDeep cenv f g env isInner body tps |> List.iter (fun tp -> tp.Constraints |> List.iter (CheckTypeConstraintDeep cenv f g env)) | TType_measure _ -> () - | TType_app (tcref, tinst, _) -> - match visitTyconRefOpt with - | Some visitTyconRef -> visitTyconRef isInner tcref + | TType_app (tcref, tinst, _) -> + match visitTyconRefOpt with + | Some visitTyconRef -> visitTyconRef isInner tcref | None -> () // If it's a 'byref<'T>', don't check 'T as an inner. This allows byref>. @@ -384,11 +384,11 @@ let rec CheckTypeDeep (cenv: cenv) (visitTy, visitTyconRefOpt, visitAppTyOpt, vi else CheckTypesDeep cenv f g env tinst - match visitAppTyOpt with + match visitAppTyOpt with | Some visitAppTy -> visitAppTy (tcref, tinst) | None -> () - | TType_anon (anonInfo, tys) -> + | TType_anon (anonInfo, tys) -> RecordAnonRecdInfo cenv anonInfo CheckTypesDeep cenv f g env tys @@ -402,91 +402,91 @@ let rec CheckTypeDeep (cenv: cenv) (visitTy, visitTyconRefOpt, visitAppTyOpt, vi CheckTypeDeep cenv f g env true s CheckTypeDeep cenv f g env true t - | TType_var (tp, _) -> - if not tp.IsSolved then - match visitTyparOpt with + | TType_var (tp, _) -> + if not tp.IsSolved then + match visitTyparOpt with | None -> () - | Some visitTyar -> + | Some visitTyar -> visitTyar (env, tp) -and CheckTypesDeep cenv f g env tys = +and CheckTypesDeep cenv f g env tys = for ty in tys do CheckTypeDeep cenv f g env true ty -and CheckTypesDeepNoInner cenv f g env tys = +and CheckTypesDeepNoInner cenv f g env tys = for ty in tys do CheckTypeDeep cenv f g env false ty and CheckTypeConstraintDeep cenv f g env x = - match x with + match x with | TyparConstraint.CoercesTo(ty, _) -> CheckTypeDeep cenv f g env true ty | TyparConstraint.MayResolveMember(traitInfo, _) -> CheckTraitInfoDeep cenv f g env traitInfo | TyparConstraint.DefaultsTo(_, ty, _) -> CheckTypeDeep cenv f g env true ty | TyparConstraint.SimpleChoice(tys, _) -> CheckTypesDeep cenv f g env tys | TyparConstraint.IsEnum(underlyingTy, _) -> CheckTypeDeep cenv f g env true underlyingTy | TyparConstraint.IsDelegate(argTys, retTy, _) -> CheckTypeDeep cenv f g env true argTys; CheckTypeDeep cenv f g env true retTy - | TyparConstraint.SupportsComparison _ - | TyparConstraint.SupportsEquality _ - | TyparConstraint.SupportsNull _ - | TyparConstraint.IsNonNullableStruct _ + | TyparConstraint.SupportsComparison _ + | TyparConstraint.SupportsEquality _ + | TyparConstraint.SupportsNull _ + | TyparConstraint.IsNonNullableStruct _ | TyparConstraint.IsUnmanaged _ - | TyparConstraint.IsReferenceType _ + | TyparConstraint.IsReferenceType _ | TyparConstraint.RequiresDefaultConstructor _ -> () -and CheckTraitInfoDeep cenv (_, _, _, visitTraitSolutionOpt, _ as f) g env (TTrait(tys, _, _, argTys, retTy, soln)) = - CheckTypesDeep cenv f g env tys - CheckTypesDeep cenv f g env argTys +and CheckTraitInfoDeep cenv (_, _, _, visitTraitSolutionOpt, _ as f) g env (TTrait(tys, _, _, argTys, retTy, soln)) = + CheckTypesDeep cenv f g env tys + CheckTypesDeep cenv f g env argTys Option.iter (CheckTypeDeep cenv f g env true ) retTy - match visitTraitSolutionOpt, soln.Value with + match visitTraitSolutionOpt, soln.Value with | Some visitTraitSolution, Some sln -> visitTraitSolution sln | _ -> () /// Check for byref-like types -let CheckForByrefLikeType cenv env m ty check = +let CheckForByrefLikeType cenv env m ty check = CheckTypeDeep cenv (ignore, Some (fun _deep tcref -> if isByrefLikeTyconRef cenv.g m tcref then check()), None, None, None) cenv.g env false ty /// Check for byref types -let CheckForByrefType cenv env ty check = +let CheckForByrefType cenv env ty check = CheckTypeDeep cenv (ignore, Some (fun _deep tcref -> if isByrefTyconRef cenv.g tcref then check()), None, None, None) cenv.g env false ty /// check captures under lambdas /// -/// This is the definition of what can/can't be free in a lambda expression. This is checked at lambdas OR TBind(v, e) nodes OR TObjExprMethod nodes. -/// For TBind(v, e) nodes we may know an 'arity' which gives as a larger set of legitimate syntactic arguments for a lambda. -/// For TObjExprMethod(v, e) nodes we always know the legitimate syntactic arguments. +/// This is the definition of what can/can't be free in a lambda expression. This is checked at lambdas OR TBind(v, e) nodes OR TObjExprMethod nodes. +/// For TBind(v, e) nodes we may know an 'arity' which gives as a larger set of legitimate syntactic arguments for a lambda. +/// For TObjExprMethod(v, e) nodes we always know the legitimate syntactic arguments. let CheckEscapes cenv allowProtected m syntacticArgs body = (* m is a range suited to error reporting *) - if cenv.reportErrors then - let cantBeFree (v: Val) = - // If v is a syntactic argument, then it can be free since it was passed in. - // The following can not be free: - // a) BaseVal can never escape. - // b) Byref typed values can never escape. + if cenv.reportErrors then + let cantBeFree (v: Val) = + // If v is a syntactic argument, then it can be free since it was passed in. + // The following can not be free: + // a) BaseVal can never escape. + // b) Byref typed values can never escape. // Note that: Local mutables can be free, as they will be boxed later. - // These checks must correspond to the tests governing the error messages below. + // These checks must correspond to the tests governing the error messages below. (v.IsBaseVal || isByrefLikeTy cenv.g m v.Type) && not (ListSet.contains valEq v syntacticArgs) let frees = freeInExpr (CollectLocalsWithStackGuard()) body - let fvs = frees.FreeLocals + let fvs = frees.FreeLocals if not allowProtected && frees.UsesMethodLocalConstructs then errorR(Error(FSComp.SR.chkProtectedOrBaseCalled(), m)) - elif Zset.exists cantBeFree fvs then - let v = List.find cantBeFree (Zset.elements fvs) + elif Zset.exists cantBeFree fvs then + let v = List.find cantBeFree (Zset.elements fvs) - // byref error before mutable error (byrefs are mutable...). + // byref error before mutable error (byrefs are mutable...). if (isByrefLikeTy cenv.g m v.Type) then - // Inner functions are not guaranteed to compile to method with a predictable arity (number of arguments). - // As such, partial applications involving byref arguments could lead to closures containing byrefs. - // For safety, such functions are assumed to have no known arity, and so can not accept byrefs. + // Inner functions are not guaranteed to compile to method with a predictable arity (number of arguments). + // As such, partial applications involving byref arguments could lead to closures containing byrefs. + // For safety, such functions are assumed to have no known arity, and so can not accept byrefs. errorR(Error(FSComp.SR.chkByrefUsedInInvalidWay(v.DisplayName), m)) elif v.IsBaseVal then errorR(Error(FSComp.SR.chkBaseUsedInInvalidWay(), m)) else - // Should be dead code, unless governing tests change + // Should be dead code, unless governing tests change errorR(InternalError(FSComp.SR.chkVariableUsedInInvalidWay(v.DisplayName), m)) Some frees else @@ -498,17 +498,17 @@ let AccessInternalsVisibleToAsInternal thisCompPath internalsVisibleToPaths acce // Each internalsVisibleToPath is a compPath for the internals of some assembly. // Replace those by the compPath for the internals of this assembly. // This makes those internals visible here, but still internal. Bug://3737 - (access, internalsVisibleToPaths) ||> List.fold (fun access internalsVisibleToPath -> + (access, internalsVisibleToPaths) ||> List.fold (fun access internalsVisibleToPath -> accessSubstPaths (thisCompPath, internalsVisibleToPath) access) - + let CheckTypeForAccess (cenv: cenv) env objName valAcc m ty = - if cenv.reportErrors then + if cenv.reportErrors then - let visitType ty = - // We deliberately only check the fully stripped type for accessibility, + let visitType ty = + // We deliberately only check the fully stripped type for accessibility, // because references to private type abbreviations are permitted - match tryTcrefOfAppTy cenv.g ty with + match tryTcrefOfAppTy cenv.g ty with | ValueNone -> () | ValueSome tcref -> let thisCompPath = compPathOfCcu cenv.viewCcu @@ -519,12 +519,12 @@ let CheckTypeForAccess (cenv: cenv) env objName valAcc m ty = CheckTypeDeep cenv (visitType, None, None, None, None) cenv.g env false ty let WarnOnWrongTypeForAccess (cenv: cenv) env objName valAcc m ty = - if cenv.reportErrors then + if cenv.reportErrors then - let visitType ty = - // We deliberately only check the fully stripped type for accessibility, + let visitType ty = + // We deliberately only check the fully stripped type for accessibility, // because references to private type abbreviations are permitted - match tryTcrefOfAppTy cenv.g ty with + match tryTcrefOfAppTy cenv.g ty with | ValueNone -> () | ValueSome tcref -> let thisCompPath = compPathOfCcu cenv.viewCcu @@ -534,11 +534,11 @@ let WarnOnWrongTypeForAccess (cenv: cenv) env objName valAcc m ty = let warningText = errorText + Environment.NewLine + FSComp.SR.tcTypeAbbreviationsCheckedAtCompileTime() warning(AttributeChecking.ObsoleteWarning(warningText, m)) - CheckTypeDeep cenv (visitType, None, None, None, None) cenv.g env false ty + CheckTypeDeep cenv (visitType, None, None, None, None) cenv.g env false ty /// Indicates whether a byref or byref-like type is permitted at a particular location [] -type PermitByRefType = +type PermitByRefType = /// Don't permit any byref or byref-like types | None @@ -551,14 +551,14 @@ type PermitByRefType = /// Permit all byref and byref-like types | All - + /// Indicates whether an address-of operation is permitted at a particular location [] -type PermitByRefExpr = +type PermitByRefExpr = /// Permit a tuple of arguments where elements can be byrefs - | YesTupleOfArgs of int + | YesTupleOfArgs of int - /// Context allows for byref typed expr. + /// Context allows for byref typed expr. | Yes /// Context allows for byref typed expr, but the byref must be returnable @@ -567,19 +567,19 @@ type PermitByRefExpr = /// Context allows for byref typed expr, but the byref must be returnable and a non-local | YesReturnableNonLocal - /// General (address-of expr and byref values not allowed) - | No + /// General (address-of expr and byref values not allowed) + | No - member ctxt.Disallow = - match ctxt with - | PermitByRefExpr.Yes - | PermitByRefExpr.YesReturnable - | PermitByRefExpr.YesReturnableNonLocal -> false + member ctxt.Disallow = + match ctxt with + | PermitByRefExpr.Yes + | PermitByRefExpr.YesReturnable + | PermitByRefExpr.YesReturnableNonLocal -> false | _ -> true - member ctxt.PermitOnlyReturnable = - match ctxt with - | PermitByRefExpr.YesReturnable + member ctxt.PermitOnlyReturnable = + match ctxt with + | PermitByRefExpr.YesReturnable | PermitByRefExpr.YesReturnableNonLocal -> true | _ -> false @@ -591,46 +591,46 @@ type PermitByRefExpr = let inline IsLimitEscapingScope env (ctxt: PermitByRefExpr) limit = (limit.scope >= env.returnScope || (limit.IsLocal && ctxt.PermitOnlyReturnableNonLocal)) -let mkArgsPermit n = +let mkArgsPermit n = if n=1 then PermitByRefExpr.Yes else PermitByRefExpr.YesTupleOfArgs n /// Work out what byref-values are allowed at input positions to named F# functions or members -let mkArgsForAppliedVal isBaseCall (vref: ValRef) argsl = +let mkArgsForAppliedVal isBaseCall (vref: ValRef) argsl = match vref.ValReprInfo with - | Some valReprInfo -> + | Some valReprInfo -> let argArities = valReprInfo.AritiesOfArgs let argArities = if isBaseCall && argArities.Length >= 1 then List.tail argArities else argArities // Check for partial applications: arguments to partial applications don't get to use byrefs - if List.length argsl >= argArities.Length then + if List.length argsl >= argArities.Length then List.map mkArgsPermit argArities else [] - | None -> [] + | None -> [] /// Work out what byref-values are allowed at input positions to functions let rec mkArgsForAppliedExpr isBaseCall argsl x = - match stripDebugPoints (stripExpr x) with - // recognise val + match stripDebugPoints (stripExpr x) with + // recognise val | Expr.Val (vref, _, _) -> mkArgsForAppliedVal isBaseCall vref argsl - // step through instantiations - | Expr.App (f, _fty, _tyargs, [], _) -> mkArgsForAppliedExpr isBaseCall argsl f - // step through subsumption coercions - | Expr.Op (TOp.Coerce, _, [f], _) -> mkArgsForAppliedExpr isBaseCall argsl f + // step through instantiations + | Expr.App (f, _fty, _tyargs, [], _) -> mkArgsForAppliedExpr isBaseCall argsl f + // step through subsumption coercions + | Expr.Op (TOp.Coerce, _, [f], _) -> mkArgsForAppliedExpr isBaseCall argsl f | _ -> [] /// Check types occurring in the TAST. let CheckTypeAux permitByRefLike (cenv: cenv) env m ty onInnerByrefError = - if cenv.reportErrors then - let visitTyar (env, tp) = - if not (env.boundTypars.ContainsKey tp) then - if tp.IsCompilerGenerated then + if cenv.reportErrors then + let visitTyar (env, tp) = + if not (env.boundTypars.ContainsKey tp) then + if tp.IsCompilerGenerated then errorR (Error(FSComp.SR.checkNotSufficientlyGenericBecauseOfScopeAnon(), m)) else errorR (Error(FSComp.SR.checkNotSufficientlyGenericBecauseOfScope(tp.DisplayName), m)) let visitTyconRef isInner tcref = - + let isInnerByRefLike = isInner && isByrefLikeTyconRef cenv.g m tcref match permitByRefLike with @@ -642,25 +642,25 @@ let CheckTypeAux permitByRefLike (cenv: cenv) env m ty onInnerByrefError = onInnerByrefError () | _ -> () - if tyconRefEq cenv.g cenv.g.system_Void_tcref tcref then + if tyconRefEq cenv.g cenv.g.system_Void_tcref tcref then errorR(Error(FSComp.SR.chkSystemVoidOnlyInTypeof(), m)) // check if T contains byref types in case of byref - let visitAppTy (tcref, tinst) = + let visitAppTy (tcref, tinst) = if isByrefLikeTyconRef cenv.g m tcref then let visitType ty0 = match tryTcrefOfAppTy cenv.g ty0 with | ValueNone -> () - | ValueSome tcref2 -> - if isByrefTyconRef cenv.g tcref2 then - errorR(Error(FSComp.SR.chkNoByrefsOfByrefs(NicePrint.minimalStringOfType cenv.denv ty), m)) + | ValueSome tcref2 -> + if isByrefTyconRef cenv.g tcref2 then + errorR(Error(FSComp.SR.chkNoByrefsOfByrefs(NicePrint.minimalStringOfType cenv.denv ty), m)) CheckTypesDeep cenv (visitType, None, None, None, None) cenv.g env tinst - let visitTraitSolution info = - match info with - | FSMethSln(_, vref, _, _) -> + let visitTraitSolution info = + match info with + | FSMethSln(_, vref, _, _) -> //printfn "considering %s..." vref.DisplayName - if valRefInThisAssembly cenv.g.compilingFSharpCore vref && not (cenv.boundVals.ContainsKey(vref.Stamp)) then + if valRefInThisAssembly cenv.g.compilingFSharpCore vref && not (cenv.boundVals.ContainsKey(vref.Stamp)) then //printfn "recording %s..." vref.DisplayName cenv.potentialUnboundUsesOfVals <- cenv.potentialUnboundUsesOfVals.Add(vref.Stamp, m) | _ -> () @@ -671,7 +671,7 @@ let CheckType permitByRefLike cenv env m ty = CheckTypeAux permitByRefLike cenv env m ty (fun () -> errorR(Error(FSComp.SR.chkErrorUseOfByref(), m))) /// Check types occurring in TAST (like CheckType) and additionally reject any byrefs. -/// The additional byref checks are to catch "byref instantiations" - one place were byref are not permitted. +/// The additional byref checks are to catch "byref instantiations" - one place were byref are not permitted. let CheckTypeNoByrefs (cenv: cenv) env m ty = CheckType PermitByRefType.None cenv env m ty /// Check types occurring in TAST but allow a Span or similar @@ -690,21 +690,21 @@ let CheckTypeInstNoInnerByrefs cenv env m tyargs = tyargs |> List.iter (CheckTypeNoInnerByrefs cenv env m) /// Applied functions get wrapped in coerce nodes for subsumption coercions -let (|OptionalCoerce|) expr = +let (|OptionalCoerce|) expr = match stripDebugPoints expr with - | Expr.Op (TOp.Coerce, _, [DebugPoints(Expr.App (f, _, _, [], _), _)], _) -> f + | Expr.Op (TOp.Coerce, _, [DebugPoints(Expr.App (f, _, _, [], _), _)], _) -> f | _ -> expr /// Check an expression doesn't contain a 'reraise' -let CheckNoReraise cenv freesOpt (body: Expr) = +let CheckNoReraise cenv freesOpt (body: Expr) = if cenv.reportErrors then - // Avoid recomputing the free variables + // Avoid recomputing the free variables let fvs = match freesOpt with None -> freeInExpr CollectLocals body | Some fvs -> fvs if fvs.UsesUnboundRethrow then errorR(Error(FSComp.SR.chkErrorContainsCallToRethrow(), body.Range)) /// Check if a function is a quotation splice operator -let isSpliceOperator g v = valRefEq g v g.splice_expr_vref || valRefEq g v g.splice_raw_expr_vref +let isSpliceOperator g v = valRefEq g v g.splice_expr_vref || valRefEq g v g.splice_raw_expr_vref /// Examples: @@ -722,11 +722,11 @@ type TTypeEquality = | NotEqual let compareTypesWithRegardToTypeVariablesAndMeasures g amap m ty1 ty2 = - + if (typeEquiv g ty1 ty2) then ExactlyEqual else - if (typeEquiv g ty1 ty2 || TypesFeasiblyEquivStripMeasures g amap m ty1 ty2) then + if (typeEquiv g ty1 ty2 || TypesFeasiblyEquivStripMeasures g amap m ty1 ty2) then FeasiblyEqual else NotEqual @@ -773,9 +773,9 @@ let rec CheckExprNoByrefs cenv env expr = CheckExpr cenv env expr PermitByRefExpr.No |> ignore /// Check a value -and CheckValRef (cenv: cenv) (env: env) v m (ctxt: PermitByRefExpr) = +and CheckValRef (cenv: cenv) (env: env) v m (ctxt: PermitByRefExpr) = - if cenv.reportErrors then + if cenv.reportErrors then if isSpliceOperator cenv.g v && not env.quote then errorR(Error(FSComp.SR.chkSplicingOnlyInQuotations(), m)) if isSpliceOperator cenv.g v then errorR(Error(FSComp.SR.chkNoFirstClassSplicing(), m)) if valRefEq cenv.g v cenv.g.addrof_vref then errorR(Error(FSComp.SR.chkNoFirstClassAddressOf(), m)) @@ -787,8 +787,8 @@ and CheckValRef (cenv: cenv) (env: env) v m (ctxt: PermitByRefExpr) = if valRefEq cenv.g v cenv.g.refcell_incr_vref then informationalWarning(Error(FSComp.SR.chkInfoRefcellIncr(), m)) if valRefEq cenv.g v cenv.g.refcell_decr_vref then informationalWarning(Error(FSComp.SR.chkInfoRefcellDecr(), m)) - // ByRefLike-typed values can only occur in permitting ctxts - if ctxt.Disallow && isByrefLikeTy cenv.g m v.Type then + // ByRefLike-typed values can only occur in permitting ctxts + if ctxt.Disallow && isByrefLikeTy cenv.g m v.Type then errorR(Error(FSComp.SR.chkNoByrefAtThisPoint(v.DisplayName), m)) if env.isInAppExpr then @@ -797,30 +797,30 @@ and CheckValRef (cenv: cenv) (env: env) v m (ctxt: PermitByRefExpr) = CheckTypeNoInnerByrefs cenv env m v.Type /// Check a use of a value -and CheckValUse (cenv: cenv) (env: env) (vref: ValRef, vFlags, m) (ctxt: PermitByRefExpr) = - +and CheckValUse (cenv: cenv) (env: env) (vref: ValRef, vFlags, m) (ctxt: PermitByRefExpr) = + let g = cenv.g let limit = GetLimitVal cenv env m vref.Deref - if cenv.reportErrors then + if cenv.reportErrors then - if vref.IsBaseVal then + if vref.IsBaseVal then errorR(Error(FSComp.SR.chkLimitationsOfBaseKeyword(), m)) - let isCallOfConstructorOfAbstractType = - (match vFlags with NormalValUse -> true | _ -> false) && - vref.IsConstructor && + let isCallOfConstructorOfAbstractType = + (match vFlags with NormalValUse -> true | _ -> false) && + vref.IsConstructor && (match vref.TryDeclaringEntity with Parent tcref -> isAbstractTycon tcref.Deref | _ -> false) - if isCallOfConstructorOfAbstractType then + if isCallOfConstructorOfAbstractType then errorR(Error(FSComp.SR.tcAbstractTypeCannotBeInstantiated(), m)) // This is used to handle this case: // let x = 1 // let y = &x // &y - let isReturnExprBuiltUsingStackReferringByRefLike = + let isReturnExprBuiltUsingStackReferringByRefLike = ctxt.PermitOnlyReturnable && ((HasLimitFlag LimitFlags.ByRef limit && IsLimitEscapingScope env ctxt limit) || HasLimitFlag LimitFlags.StackReferringSpanLike limit) @@ -833,9 +833,9 @@ and CheckValUse (cenv: cenv) (env: env) (vref: ValRef, vFlags, m) (ctxt: PermitB | true, false -> errorR(Error(FSComp.SR.chkNoSpanLikeVariable(vref.DisplayName), m)) | false, true -> errorR(Error(FSComp.SR.chkNoByrefAddressOfValueFromExpression(), m)) | false, false -> errorR(Error(FSComp.SR.chkNoByrefAddressOfLocal(vref.DisplayName), m)) - - let isReturnOfStructThis = - ctxt.PermitOnlyReturnable && + + let isReturnOfStructThis = + ctxt.PermitOnlyReturnable && isByrefTy g vref.Type && (vref.IsMemberThisVal) @@ -845,9 +845,9 @@ and CheckValUse (cenv: cenv) (env: env) (vref: ValRef, vFlags, m) (ctxt: PermitB CheckValRef cenv env vref m ctxt limit - + /// Check an expression, given information about the position of the expression -and CheckForOverAppliedExceptionRaisingPrimitive (cenv: cenv) expr = +and CheckForOverAppliedExceptionRaisingPrimitive (cenv: cenv) expr = let g = cenv.g let expr = stripExpr expr let expr = stripDebugPoints expr @@ -861,12 +861,12 @@ and CheckForOverAppliedExceptionRaisingPrimitive (cenv: cenv) expr = // Special diagnostics for `raise`, `failwith`, `failwithf`, `nullArg`, `invalidOp` library intrinsics commonly used to raise exceptions // to warn on over-application. match f with - | OptionalCoerce(Expr.Val (v, _, funcRange)) + | OptionalCoerce(Expr.Val (v, _, funcRange)) when (valRefEq g v g.raise_vref || valRefEq g v g.failwith_vref || valRefEq g v g.null_arg_vref || valRefEq g v g.invalid_op_vref) -> match argsl with | [] | [_] -> () | _ :: _ :: _ -> - warning(Error(FSComp.SR.checkRaiseFamilyFunctionArgumentCount(v.DisplayName, 1, argsl.Length), funcRange)) + warning(Error(FSComp.SR.checkRaiseFamilyFunctionArgumentCount(v.DisplayName, 1, argsl.Length), funcRange)) | OptionalCoerce(Expr.Val (v, _, funcRange)) when valRefEq g v g.invalid_arg_vref -> match argsl with @@ -893,14 +893,14 @@ and CheckCallLimitArgs cenv env m returnTy limitArgs (ctxt: PermitByRefExpr) = let isReturnSpanLike = isSpanLikeTy cenv.g m returnTy // If return is a byref, and being used as a return, then a single argument cannot be a local-byref or a stack referring span-like. - let isReturnLimitedByRef = - isReturnByref && - (HasLimitFlag LimitFlags.ByRef limitArgs || + let isReturnLimitedByRef = + isReturnByref && + (HasLimitFlag LimitFlags.ByRef limitArgs || HasLimitFlag LimitFlags.StackReferringSpanLike limitArgs) // If return is a byref, and being used as a return, then a single argument cannot be a stack referring span-like or a local-byref of a stack referring span-like. - let isReturnLimitedSpanLike = - isReturnSpanLike && + let isReturnLimitedSpanLike = + isReturnSpanLike && (HasLimitFlag LimitFlags.StackReferringSpanLike limitArgs || HasLimitFlag LimitFlags.ByRefOfStackReferringSpanLike limitArgs) @@ -911,11 +911,11 @@ and CheckCallLimitArgs cenv env m returnTy limitArgs (ctxt: PermitByRefExpr) = else errorR(Error(FSComp.SR.chkNoByrefAddressOfValueFromExpression(), m)) - // You cannot call a function that takes a byref of a span-like (not stack referring) and + // You cannot call a function that takes a byref of a span-like (not stack referring) and // either a stack referring span-like or a local-byref of a stack referring span-like. - let isCallLimited = - HasLimitFlag LimitFlags.ByRefOfSpanLike limitArgs && - (HasLimitFlag LimitFlags.StackReferringSpanLike limitArgs || + let isCallLimited = + HasLimitFlag LimitFlags.ByRefOfSpanLike limitArgs && + (HasLimitFlag LimitFlags.StackReferringSpanLike limitArgs || HasLimitFlag LimitFlags.ByRefOfStackReferringSpanLike limitArgs) if isCallLimited then @@ -965,7 +965,7 @@ and CheckCallWithReceiver cenv env m returnTy args ctxts ctxt = | ctxt :: ctxts -> ctxt, ctxts let receiverLimit = CheckExpr cenv env receiverArg receiverContext - let limitArgs = + let limitArgs = let limitArgs = CheckExprs cenv env args ctxts // We do not include the receiver's limit in the limit args unless the receiver is a stack referring span-like. if HasLimitFlag LimitFlags.ByRefOfStackReferringSpanLike receiverLimit then @@ -975,9 +975,9 @@ and CheckCallWithReceiver cenv env m returnTy args ctxts ctxt = limitArgs CheckCallLimitArgs cenv env m returnTy limitArgs ctxt -and CheckExprLinear (cenv: cenv) (env: env) expr (ctxt: PermitByRefExpr) (contf : Limit -> Limit) = +and CheckExprLinear (cenv: cenv) (env: env) expr (ctxt: PermitByRefExpr) (contf : Limit -> Limit) = match expr with - | Expr.Sequential (e1, e2, NormalSeq, _) -> + | Expr.Sequential (e1, e2, NormalSeq, _) -> CheckExprNoByrefs cenv env e1 // tailcall CheckExprLinear cenv env e2 ctxt contf @@ -991,35 +991,35 @@ and CheckExprLinear (cenv: cenv) (env: env) expr (ctxt: PermitByRefExpr) (contf else PermitByRefExpr.Yes - let limit = CheckBinding cenv { env with returnScope = env.returnScope + 1 } false bindingContext bind + let limit = CheckBinding cenv { env with returnScope = env.returnScope + 1 } false bindingContext bind BindVal cenv env v LimitVal cenv v { limit with scope = if isByRef then limit.scope else env.returnScope } // tailcall - CheckExprLinear cenv env body ctxt contf + CheckExprLinear cenv env body ctxt contf | LinearOpExpr (_op, tyargs, argsHead, argLast, m) -> CheckTypeInstNoByrefs cenv env m tyargs - argsHead |> List.iter (CheckExprNoByrefs cenv env) + argsHead |> List.iter (CheckExprNoByrefs cenv env) // tailcall CheckExprLinear cenv env argLast PermitByRefExpr.No (fun _ -> contf NoLimit) | LinearMatchExpr (_spMatch, _exprm, dtree, tg1, e2, m, ty) -> - CheckTypeNoInnerByrefs cenv env m ty + CheckTypeNoInnerByrefs cenv env m ty CheckDecisionTree cenv env dtree let lim1 = CheckDecisionTreeTarget cenv env ctxt tg1 // tailcall CheckExprLinear cenv env e2 ctxt (fun lim2 -> contf (CombineLimits [ lim1; lim2 ])) - | Expr.DebugPoint (_, innerExpr) -> + | Expr.DebugPoint (_, innerExpr) -> CheckExprLinear cenv env innerExpr ctxt contf - | _ -> + | _ -> // not a linear expression contf (CheckExpr cenv env expr ctxt) /// Check a resumable code expression (the body of a ResumableCode delegate or /// the body of the MoveNextMethod for a state machine) -and TryCheckResumableCodeConstructs cenv env expr : bool = +and TryCheckResumableCodeConstructs cenv env expr : bool = let g = cenv.g match env.resumableCode with @@ -1029,14 +1029,14 @@ and TryCheckResumableCodeConstructs cenv env expr : bool = | Resumable.ResumableExpr allowed -> match expr with | IfUseResumableStateMachinesExpr g (thenExpr, elseExpr) -> - CheckExprNoByrefs cenv { env with resumableCode = Resumable.ResumableExpr true } thenExpr - CheckExprNoByrefs cenv { env with resumableCode = Resumable.None } elseExpr + CheckExprNoByrefs cenv { env with resumableCode = Resumable.ResumableExpr true } thenExpr + CheckExprNoByrefs cenv { env with resumableCode = Resumable.None } elseExpr true | ResumableEntryMatchExpr g (noneBranchExpr, someVar, someBranchExpr, _rebuild) -> if not allowed then errorR(Error(FSComp.SR.tcInvalidResumableConstruct("__resumableEntry"), expr.Range)) - CheckExprNoByrefs cenv env noneBranchExpr + CheckExprNoByrefs cenv env noneBranchExpr BindVal cenv env someVar CheckExprNoByrefs cenv env someBranchExpr true @@ -1083,7 +1083,7 @@ and TryCheckResumableCodeConstructs cenv env expr : bool = true | Expr.Match (_spBind, _exprm, dtree, targets, _m, _ty) -> - targets |> Array.iter(fun (TTarget(vs, targetExpr, _)) -> + targets |> Array.iter(fun (TTarget(vs, targetExpr, _)) -> BindVals cenv env vs CheckExprNoByrefs cenv env targetExpr) CheckDecisionTree cenv { env with resumableCode = Resumable.None } dtree @@ -1096,29 +1096,29 @@ and TryCheckResumableCodeConstructs cenv env expr : bool = BindVal cenv env bind.Var CheckExprNoByrefs cenv env bodyExpr true - + // LetRec bindings may not appear as part of resumable code (more careful work is needed to make them compilable) - | Expr.LetRec(_bindings, bodyExpr, _range, _frees) when allowed -> + | Expr.LetRec(_bindings, bodyExpr, _range, _frees) when allowed -> errorR(Error(FSComp.SR.tcResumableCodeContainsLetRec(), expr.Range)) CheckExprNoByrefs cenv env bodyExpr true // This construct arises from the 'mkDefault' in the 'Throw' case of an incomplete pattern match - | Expr.Const (Const.Zero, _, _) -> + | Expr.Const (Const.Zero, _, _) -> true - | Expr.DebugPoint (_, innerExpr) -> + | Expr.DebugPoint (_, innerExpr) -> TryCheckResumableCodeConstructs cenv env innerExpr | _ -> false /// Check an expression, given information about the position of the expression -and CheckExpr (cenv: cenv) (env: env) origExpr (ctxt: PermitByRefExpr) : Limit = - +and CheckExpr (cenv: cenv) (env: env) origExpr (ctxt: PermitByRefExpr) : Limit = + // Guard the stack for deeply nested expressions cenv.stackGuard.Guard <| fun () -> - + let g = cenv.g let origExpr = stripExpr origExpr @@ -1129,64 +1129,64 @@ and CheckExpr (cenv: cenv) (env: env) origExpr (ctxt: PermitByRefExpr) : Limit = let expr = stripExpr expr match TryCheckResumableCodeConstructs cenv env expr with - | true -> + | true -> // we've handled the special cases of resumable code and don't do other checks. - NoLimit - | false -> + NoLimit + | false -> // Handle ResumableExpr --> other expression let env = { env with resumableCode = Resumable.None } match expr with - | LinearOpExpr _ - | LinearMatchExpr _ - | Expr.Let _ + | LinearOpExpr _ + | LinearMatchExpr _ + | Expr.Let _ | Expr.Sequential (_, _, NormalSeq, _) - | Expr.DebugPoint _ -> + | Expr.DebugPoint _ -> CheckExprLinear cenv env expr ctxt id - | Expr.Sequential (e1, e2, ThenDoSeq, _) -> + | Expr.Sequential (e1, e2, ThenDoSeq, _) -> CheckExprNoByrefs cenv env e1 CheckExprNoByrefs cenv env e2 NoLimit - | Expr.Const (_, m, ty) -> - CheckTypeNoInnerByrefs cenv env m ty + | Expr.Const (_, m, ty) -> + CheckTypeNoInnerByrefs cenv env m ty NoLimit - - | Expr.Val (vref, vFlags, m) -> + + | Expr.Val (vref, vFlags, m) -> CheckValUse cenv env (vref, vFlags, m) ctxt - - | Expr.Quote (ast, savedConv, _isFromQueryExpression, m, ty) -> + + | Expr.Quote (ast, savedConv, _isFromQueryExpression, m, ty) -> CheckQuoteExpr cenv env (ast, savedConv, m, ty) | StructStateMachineExpr g info -> CheckStructStateMachineExpr cenv env expr info - | Expr.Obj (_, ty, basev, superInitCall, overrides, iimpls, m) -> + | Expr.Obj (_, ty, basev, superInitCall, overrides, iimpls, m) -> CheckObjectExpr cenv env (ty, basev, superInitCall, overrides, iimpls, m) // Allow base calls to F# methods - | Expr.App (InnerExprPat(ExprValWithPossibleTypeInst(v, vFlags, _, _) as f), _fty, tyargs, Expr.Val (baseVal, _, _) :: rest, m) - when ((match vFlags with VSlotDirectCall -> true | _ -> false) && + | Expr.App (InnerExprPat(ExprValWithPossibleTypeInst(v, vFlags, _, _) as f), _fty, tyargs, Expr.Val (baseVal, _, _) :: rest, m) + when ((match vFlags with VSlotDirectCall -> true | _ -> false) && baseVal.IsBaseVal) -> CheckFSharpBaseCall cenv env expr (v, f, _fty, tyargs, baseVal, rest, m) // Allow base calls to IL methods - | Expr.Op (TOp.ILCall (isVirtual, _, _, _, _, _, _, ilMethRef, enclTypeInst, methInst, retTypes), tyargs, Expr.Val (baseVal, _, _) :: rest, m) + | Expr.Op (TOp.ILCall (isVirtual, _, _, _, _, _, _, ilMethRef, enclTypeInst, methInst, retTypes), tyargs, Expr.Val (baseVal, _, _) :: rest, m) when not isVirtual && baseVal.IsBaseVal -> - + CheckILBaseCall cenv env (ilMethRef, enclTypeInst, methInst, retTypes, tyargs, baseVal, rest, m) | Expr.Op (op, tyargs, args, m) -> CheckExprOp cenv env (op, tyargs, args, m) ctxt expr - // Allow 'typeof' calls as a special case, the only accepted use of System.Void! + // Allow 'typeof' calls as a special case, the only accepted use of System.Void! | TypeOfExpr g ty when isVoidTy g ty -> NoLimit - // Allow 'typedefof' calls as a special case, the only accepted use of System.Void! + // Allow 'typedefof' calls as a special case, the only accepted use of System.Void! | TypeDefOfExpr g ty when isVoidTy g ty -> NoLimit @@ -1198,65 +1198,65 @@ and CheckExpr (cenv: cenv) (env: env) origExpr (ctxt: PermitByRefExpr) : Limit = | Expr.App (f, _fty, tyargs, argsl, m) -> CheckApplication cenv env expr (f, tyargs, argsl, m) ctxt - | Expr.Lambda (_, _, _, argvs, _, m, bodyTy) -> + | Expr.Lambda (_, _, _, argvs, _, m, bodyTy) -> CheckLambda cenv env expr (argvs, m, bodyTy) - | Expr.TyLambda (_, tps, _, m, bodyTy) -> + | Expr.TyLambda (_, tps, _, m, bodyTy) -> CheckTyLambda cenv env expr (tps, m, bodyTy) - | Expr.TyChoose (tps, e1, _) -> - let env = BindTypars g env tps - CheckExprNoByrefs cenv env e1 + | Expr.TyChoose (tps, e1, _) -> + let env = BindTypars g env tps + CheckExprNoByrefs cenv env e1 NoLimit - | Expr.Match (_, _, dtree, targets, m, ty) -> + | Expr.Match (_, _, dtree, targets, m, ty) -> CheckMatch cenv env ctxt (dtree, targets, m, ty) - | Expr.LetRec (binds, bodyExpr, _, _) -> + | Expr.LetRec (binds, bodyExpr, _, _) -> CheckLetRec cenv env (binds, bodyExpr) - | Expr.StaticOptimization (constraints, e2, e3, m) -> + | Expr.StaticOptimization (constraints, e2, e3, m) -> CheckStaticOptimization cenv env (constraints, e2, e3, m) | Expr.WitnessArg _ -> NoLimit - | Expr.Link _ -> + | Expr.Link _ -> failwith "Unexpected reclink" and CheckQuoteExpr cenv env (ast, savedConv, m, ty) = let g = cenv.g CheckExprNoByrefs cenv {env with quote=true} ast - if cenv.reportErrors then + if cenv.reportErrors then cenv.usesQuotations <- true // Translate the quotation to quotation data - try - let doData suppressWitnesses = - let qscope = QuotationTranslator.QuotationGenerationScope.Create (g, cenv.amap, cenv.viewCcu, cenv.tcVal, QuotationTranslator.IsReflectedDefinition.No) - let qdata = QuotationTranslator.ConvExprPublic qscope suppressWitnesses ast + try + let doData suppressWitnesses = + let qscope = QuotationTranslator.QuotationGenerationScope.Create (g, cenv.amap, cenv.viewCcu, cenv.tcVal, QuotationTranslator.IsReflectedDefinition.No) + let qdata = QuotationTranslator.ConvExprPublic qscope suppressWitnesses ast let typeDefs, spliceTypes, spliceExprs = qscope.Close() typeDefs, List.map fst spliceTypes, List.map fst spliceExprs, qdata let data1 = doData true let data2 = doData false - match savedConv.Value with + match savedConv.Value with | None -> savedConv.Value <- Some (data1, data2) | Some _ -> () - with QuotationTranslator.InvalidQuotedTerm e -> + with QuotationTranslator.InvalidQuotedTerm e -> errorRecovery e m - + CheckTypeNoByrefs cenv env m ty NoLimit and CheckStructStateMachineExpr cenv env expr info = let g = cenv.g - let (_dataTy, - (moveNextThisVar, moveNextExpr), - (setStateMachineThisVar, setStateMachineStateVar, setStateMachineBody), + let (_dataTy, + (moveNextThisVar, moveNextExpr), + (setStateMachineThisVar, setStateMachineStateVar, setStateMachineBody), (afterCodeThisVar, afterCodeBody)) = info if not (g.langVersion.SupportsFeature LanguageFeature.ResumableStateMachines) then @@ -1275,8 +1275,8 @@ and CheckObjectExpr cenv env (ty, basev, superInitCall, overrides, iimpls, m) = CheckInterfaceImpls cenv env basev iimpls CheckTypeNoByrefs cenv env m ty - let interfaces = - [ if isInterfaceTy g ty then + let interfaces = + [ if isInterfaceTy g ty then yield! AllSuperTypesOfType g cenv.amap m AllowMultiIntfInstantiations.Yes ty for ty, _ in iimpls do yield! AllSuperTypesOfType g cenv.amap m AllowMultiIntfInstantiations.Yes ty ] @@ -1291,7 +1291,7 @@ and CheckFSharpBaseCall cenv env expr (v, f, _fty, tyargs, baseVal, rest, m) = if memberInfo.MemberFlags.IsDispatchSlot then errorR(Error(FSComp.SR.tcCannotCallAbstractBaseMember(v.DisplayName), m)) NoLimit - else + else let env = { env with isInAppExpr = true } let returnTy = tyOfExpr g expr @@ -1301,9 +1301,9 @@ and CheckFSharpBaseCall cenv env expr (v, f, _fty, tyargs, baseVal, rest, m) = CheckTypeNoInnerByrefs cenv env m returnTy CheckExprs cenv env rest (mkArgsForAppliedExpr true rest f) -and CheckILBaseCall cenv env (ilMethRef, enclTypeInst, methInst, retTypes, tyargs, baseVal, rest, m) = +and CheckILBaseCall cenv env (ilMethRef, enclTypeInst, methInst, retTypes, tyargs, baseVal, rest, m) = let g = cenv.g - // Disallow calls to abstract base methods on IL types. + // Disallow calls to abstract base methods on IL types. match tryTcrefOfAppTy g baseVal.Type with | ValueSome tcref when tcref.IsILTycon -> try @@ -1324,14 +1324,14 @@ and CheckILBaseCall cenv env (ilMethRef, enclTypeInst, methInst, retTypes, tyarg CheckValRef cenv env baseVal m PermitByRefExpr.No CheckExprsPermitByRefLike cenv env rest -and CheckSpliceApplication cenv env (tinst, arg, m) = +and CheckSpliceApplication cenv env (tinst, arg, m) = CheckTypeInstNoInnerByrefs cenv env m tinst // it's the splice operator, a byref instantiation is allowed CheckExprNoByrefs cenv env arg NoLimit -and CheckApplication cenv env expr (f, tyargs, argsl, m) ctxt = +and CheckApplication cenv env expr (f, tyargs, argsl, m) ctxt = let g = cenv.g - match expr with + match expr with | ResumableCodeInvoke g _ -> warning(Error(FSComp.SR.tcResumableCodeInvocation(), m)) | _ -> () @@ -1358,43 +1358,43 @@ and CheckApplication cenv env expr (f, tyargs, argsl, m) ctxt = else CheckCall cenv env m returnTy argsl ctxts ctxt -and CheckLambda cenv env expr (argvs, m, bodyTy) = - let valReprInfo = ValReprInfo ([], [argvs |> List.map (fun _ -> ValReprInfo.unnamedTopArg1)], ValReprInfo.unnamedRetVal) - let ty = mkMultiLambdaTy cenv.g m argvs bodyTy in +and CheckLambda cenv env expr (argvs, m, bodyTy) = + let valReprInfo = ValReprInfo ([], [argvs |> List.map (fun _ -> ValReprInfo.unnamedTopArg1)], ValReprInfo.unnamedRetVal) + let ty = mkMultiLambdaTy cenv.g m argvs bodyTy in CheckLambdas false None cenv env false valReprInfo false expr m ty PermitByRefExpr.Yes -and CheckTyLambda cenv env expr (tps, m, bodyTy) = - let valReprInfo = ValReprInfo (ValReprInfo.InferTyparInfo tps, [], ValReprInfo.unnamedRetVal) - let ty = mkForallTyIfNeeded tps bodyTy in +and CheckTyLambda cenv env expr (tps, m, bodyTy) = + let valReprInfo = ValReprInfo (ValReprInfo.InferTyparInfo tps, [], ValReprInfo.unnamedRetVal) + let ty = mkForallTyIfNeeded tps bodyTy in CheckLambdas false None cenv env false valReprInfo false expr m ty PermitByRefExpr.Yes -and CheckMatch cenv env ctxt (dtree, targets, m, ty) = +and CheckMatch cenv env ctxt (dtree, targets, m, ty) = CheckTypeNoInnerByrefs cenv env m ty // computed byrefs allowed at each branch CheckDecisionTree cenv env dtree CheckDecisionTreeTargets cenv env targets ctxt -and CheckLetRec cenv env (binds, bodyExpr) = +and CheckLetRec cenv env (binds, bodyExpr) = BindVals cenv env (valsOfBinds binds) CheckBindings cenv env binds CheckExprNoByrefs cenv env bodyExpr NoLimit -and CheckStaticOptimization cenv env (constraints, e2, e3, m) = +and CheckStaticOptimization cenv env (constraints, e2, e3, m) = CheckExprNoByrefs cenv env e2 CheckExprNoByrefs cenv env e3 constraints |> List.iter (function - | TTyconEqualsTycon(ty1, ty2) -> + | TTyconEqualsTycon(ty1, ty2) -> CheckTypeNoByrefs cenv env m ty1 CheckTypeNoByrefs cenv env m ty2 - | TTyconIsStruct ty1 -> + | TTyconIsStruct ty1 -> CheckTypeNoByrefs cenv env m ty1) NoLimit -and CheckMethods cenv env baseValOpt (ty, methods) = - methods |> List.iter (CheckMethod cenv env baseValOpt ty) +and CheckMethods cenv env baseValOpt (ty, methods) = + methods |> List.iter (CheckMethod cenv env baseValOpt ty) -and CheckMethod cenv env baseValOpt ty (TObjExprMethod(_, attribs, tps, vs, body, m)) = - let env = BindTypars cenv.g env tps +and CheckMethod cenv env baseValOpt ty (TObjExprMethod(_, attribs, tps, vs, body, m)) = + let env = BindTypars cenv.g env tps let vs = List.concat vs let env = BindArgVals env vs let env = @@ -1410,18 +1410,18 @@ and CheckMethod cenv env baseValOpt ty (TObjExprMethod(_, attribs, tps, vs, body CheckEscapes cenv true m (match baseValOpt with Some x -> x :: vs | None -> vs) body |> ignore CheckExpr cenv { env with returnScope = env.returnScope + 1 } body PermitByRefExpr.YesReturnableNonLocal |> ignore -and CheckInterfaceImpls cenv env baseValOpt l = +and CheckInterfaceImpls cenv env baseValOpt l = l |> List.iter (CheckInterfaceImpl cenv env baseValOpt) - -and CheckInterfaceImpl cenv env baseValOpt overrides = - CheckMethods cenv env baseValOpt overrides + +and CheckInterfaceImpl cenv env baseValOpt overrides = + CheckMethods cenv env baseValOpt overrides and CheckNoResumableStmtConstructs cenv _env expr = let g = cenv.g - match expr with - | Expr.Val (v, _, m) - when valRefEq g v g.cgh__resumeAt_vref || - valRefEq g v g.cgh__resumableEntry_vref || + match expr with + | Expr.Val (v, _, m) + when valRefEq g v g.cgh__resumeAt_vref || + valRefEq g v g.cgh__resumableEntry_vref || valRefEq g v g.cgh__stateMachine_vref -> errorR(Error(FSComp.SR.tcInvalidResumableConstruct(v.DisplayName), m)) | _ -> () @@ -1431,20 +1431,20 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = // Ensure anonymous record type requirements are recorded match op with - | TOp.AnonRecdGet (anonInfo, _) - | TOp.AnonRecd anonInfo -> + | TOp.AnonRecdGet (anonInfo, _) + | TOp.AnonRecd anonInfo -> RecordAnonRecdInfo cenv anonInfo | _ -> () // Special cases - match op, tyargs, args with - // Handle these as special cases since mutables are allowed inside their bodies + match op, tyargs, args with + // Handle these as special cases since mutables are allowed inside their bodies | TOp.While _, _, [Expr.Lambda (_, _, _, [_], e1, _, _);Expr.Lambda (_, _, _, [_], e2, _, _)] -> - CheckTypeInstNoByrefs cenv env m tyargs + CheckTypeInstNoByrefs cenv env m tyargs CheckExprsNoByRefLike cenv env [e1;e2] | TOp.TryFinally _, [_], [Expr.Lambda (_, _, _, [_], e1, _, _); Expr.Lambda (_, _, _, [_], e2, _, _)] -> - CheckTypeInstNoInnerByrefs cenv env m tyargs // result of a try/finally can be a byref + CheckTypeInstNoInnerByrefs cenv env m tyargs // result of a try/finally can be a byref let limit = CheckExpr cenv env e1 ctxt // result of a try/finally can be a byref if in a position where the overall expression is can be a byref CheckExprNoByrefs cenv env e2 limit @@ -1454,19 +1454,19 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = CheckExprsNoByRefLike cenv env [e1;e2;e3] | TOp.TryWith _, [_], [Expr.Lambda (_, _, _, [_], e1, _, _); Expr.Lambda (_, _, _, [_], _e2, _, _); Expr.Lambda (_, _, _, [_], e3, _, _)] -> - CheckTypeInstNoInnerByrefs cenv env m tyargs // result of a try/catch can be a byref + CheckTypeInstNoInnerByrefs cenv env m tyargs // result of a try/catch can be a byref let limit1 = CheckExpr cenv env e1 ctxt // result of a try/catch can be a byref if in a position where the overall expression is can be a byref // [(* e2; -- don't check filter body - duplicates logic in 'catch' body *) e3] let limit2 = CheckExpr cenv env e3 ctxt // result of a try/catch can be a byref if in a position where the overall expression is can be a byref CombineTwoLimits limit1 limit2 - + | TOp.ILCall (_, _, _, _, _, _, _, ilMethRef, enclTypeInst, methInst, retTypes), _, _ -> CheckTypeInstNoByrefs cenv env m tyargs CheckTypeInstNoByrefs cenv env m enclTypeInst CheckTypeInstNoByrefs cenv env m methInst CheckTypeInstNoInnerByrefs cenv env m retTypes // permit byref returns - let hasReceiver = + let hasReceiver = (ilMethRef.CallingConv.IsInstance || ilMethRef.CallingConv.IsInstanceExplicit) && not args.IsEmpty @@ -1475,46 +1475,46 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = let argContexts = List.init args.Length (fun _ -> PermitByRefExpr.Yes) match retTypes with - | [ty] when ctxt.PermitOnlyReturnable && isByrefLikeTy g m ty -> + | [ty] when ctxt.PermitOnlyReturnable && isByrefLikeTy g m ty -> if hasReceiver then CheckCallWithReceiver cenv env m returnTy args argContexts ctxt else CheckCall cenv env m returnTy args argContexts ctxt - | _ -> + | _ -> if hasReceiver then CheckCallWithReceiver cenv env m returnTy args argContexts PermitByRefExpr.Yes else CheckCall cenv env m returnTy args argContexts PermitByRefExpr.Yes - | TOp.Tuple tupInfo, _, _ when not (evalTupInfoIsStruct tupInfo) -> - match ctxt with - | PermitByRefExpr.YesTupleOfArgs nArity -> - if cenv.reportErrors then - if args.Length <> nArity then + | TOp.Tuple tupInfo, _, _ when not (evalTupInfoIsStruct tupInfo) -> + match ctxt with + | PermitByRefExpr.YesTupleOfArgs nArity -> + if cenv.reportErrors then + if args.Length <> nArity then errorR(InternalError("Tuple arity does not correspond to planned function argument arity", m)) - // This tuple should not be generated. The known function arity - // means it just bundles arguments. - CheckExprsPermitByRefLike cenv env args - | _ -> + // This tuple should not be generated. The known function arity + // means it just bundles arguments. + CheckExprsPermitByRefLike cenv env args + | _ -> CheckTypeInstNoByrefs cenv env m tyargs - CheckExprsNoByRefLike cenv env args + CheckExprsNoByRefLike cenv env args - | TOp.LValueOp (LAddrOf _, vref), _, _ -> + | TOp.LValueOp (LAddrOf _, vref), _, _ -> let limit1 = GetLimitValByRef cenv env m vref.Deref let limit2 = CheckExprsNoByRefLike cenv env args let limit = CombineTwoLimits limit1 limit2 - if cenv.reportErrors then + if cenv.reportErrors then - if ctxt.Disallow then + if ctxt.Disallow then errorR(Error(FSComp.SR.chkNoAddressOfAtThisPoint(vref.DisplayName), m)) - - let returningAddrOfLocal = - ctxt.PermitOnlyReturnable && + + let returningAddrOfLocal = + ctxt.PermitOnlyReturnable && HasLimitFlag LimitFlags.ByRef limit && IsLimitEscapingScope env ctxt limit - - if returningAddrOfLocal then + + if returningAddrOfLocal then if vref.IsCompilerGenerated then errorR(Error(FSComp.SR.chkNoByrefAddressOfValueFromExpression(), m)) else @@ -1522,15 +1522,15 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = limit - | TOp.LValueOp (LByrefSet, vref), _, [arg] -> + | TOp.LValueOp (LByrefSet, vref), _, [arg] -> let limit = GetLimitVal cenv env m vref.Deref let isVrefLimited = not (HasLimitFlag LimitFlags.ByRefOfStackReferringSpanLike limit) let isArgLimited = HasLimitFlag LimitFlags.StackReferringSpanLike (CheckExprPermitByRefLike cenv env arg) - if isVrefLimited && isArgLimited then + if isVrefLimited && isArgLimited then errorR(Error(FSComp.SR.chkNoWriteToLimitedSpan(vref.DisplayName), m)) NoLimit - | TOp.LValueOp (LByrefGet, vref), _, [] -> + | TOp.LValueOp (LByrefGet, vref), _, [] -> let limit = GetLimitVal cenv env m vref.Deref if HasLimitFlag LimitFlags.ByRefOfStackReferringSpanLike limit then @@ -1546,27 +1546,27 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = else { scope = 1; flags = LimitFlags.None } - | TOp.LValueOp (LSet, vref), _, [arg] -> + | TOp.LValueOp (LSet, vref), _, [arg] -> let isVrefLimited = not (HasLimitFlag LimitFlags.StackReferringSpanLike (GetLimitVal cenv env m vref.Deref)) let isArgLimited = HasLimitFlag LimitFlags.StackReferringSpanLike (CheckExprPermitByRefLike cenv env arg) - if isVrefLimited && isArgLimited then + if isVrefLimited && isArgLimited then errorR(Error(FSComp.SR.chkNoWriteToLimitedSpan(vref.DisplayName), m)) NoLimit | TOp.AnonRecdGet _, _, [arg1] - | TOp.TupleFieldGet _, _, [arg1] -> + | TOp.TupleFieldGet _, _, [arg1] -> CheckTypeInstNoByrefs cenv env m tyargs CheckExprsPermitByRefLike cenv env [arg1] - | TOp.ValFieldGet _rf, _, [arg1] -> + | TOp.ValFieldGet _rf, _, [arg1] -> CheckTypeInstNoByrefs cenv env m tyargs - //See mkRecdFieldGetViaExprAddr -- byref arg1 when #args =1 - // Property getters on mutable structs come through here. - CheckExprsPermitByRefLike cenv env [arg1] + //See mkRecdFieldGetViaExprAddr -- byref arg1 when #args =1 + // Property getters on mutable structs come through here. + CheckExprsPermitByRefLike cenv env [arg1] - | TOp.ValFieldSet rf, _, [arg1;arg2] -> + | TOp.ValFieldSet rf, _, [arg1;arg2] -> CheckTypeInstNoByrefs cenv env m tyargs - // See mkRecdFieldSetViaExprAddr -- byref arg1 when #args=2 + // See mkRecdFieldSetViaExprAddr -- byref arg1 when #args=2 // Field setters on mutable structs come through here let limit1 = CheckExprPermitByRefLike cenv env arg1 let limit2 = CheckExprPermitByRefLike cenv env arg2 @@ -1591,9 +1591,9 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = // Check get of static field | TOp.ValFieldGetAddr (rfref, _readonly), tyargs, [] -> - + if ctxt.Disallow && cenv.reportErrors && isByrefLikeTy g m (tyOfExpr g expr) then - errorR(Error(FSComp.SR.chkNoAddressStaticFieldAtThisPoint(rfref.FieldName), m)) + errorR(Error(FSComp.SR.chkNoAddressStaticFieldAtThisPoint(rfref.FieldName), m)) CheckTypeInstNoByrefs cenv env m tyargs NoLimit @@ -1606,24 +1606,24 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = // C# applies a rule where the APIs to struct types can't return the addresses of fields in that struct. // There seems no particular reason for this given that other protections in the language, though allowing - // it would mean "readonly" on a struct doesn't imply immutability-of-contents - it only implies + // it would mean "readonly" on a struct doesn't imply immutability-of-contents - it only implies if ctxt.PermitOnlyReturnable && (match stripDebugPoints obj with Expr.Val (vref, _, _) -> vref.IsMemberThisVal | _ -> false) && isByrefTy g (tyOfExpr g obj) then errorR(Error(FSComp.SR.chkStructsMayNotReturnAddressesOfContents(), m)) if ctxt.Disallow && cenv.reportErrors && isByrefLikeTy g m (tyOfExpr g expr) then errorR(Error(FSComp.SR.chkNoAddressFieldAtThisPoint(rfref.FieldName), m)) - // This construct is used for &(rx.rfield) and &(rx->rfield). Relax to permit byref types for rx. [See Bug 1263]. + // This construct is used for &(rx.rfield) and &(rx->rfield). Relax to permit byref types for rx. [See Bug 1263]. CheckTypeInstNoByrefs cenv env m tyargs // Recursively check in same ctxt, e.g. if at PermitOnlyReturnable the obj arg must also be returnable CheckExpr cenv env obj ctxt - | TOp.UnionCaseFieldGet _, _, [arg1] -> + | TOp.UnionCaseFieldGet _, _, [arg1] -> CheckTypeInstNoByrefs cenv env m tyargs CheckExprPermitByRefLike cenv env arg1 - | TOp.UnionCaseTagGet _, _, [arg1] -> + | TOp.UnionCaseTagGet _, _, [arg1] -> CheckTypeInstNoByrefs cenv env m tyargs CheckExprPermitByRefLike cenv env arg1 // allow byref - it may be address-of-struct @@ -1646,18 +1646,18 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = match instrs, args with // Write a .NET instance field | [ I_stfld (_alignment, _vol, _fspec) ], _ -> - // permit byref for lhs lvalue + // permit byref for lhs lvalue // permit byref for rhs lvalue (field would have to have ByRefLike type, i.e. be a field in another ByRefLike type) CheckExprsPermitByRefLike cenv env args // Read a .NET instance field | [ I_ldfld (_alignment, _vol, _fspec) ], _ -> - // permit byref for lhs lvalue + // permit byref for lhs lvalue CheckExprsPermitByRefLike cenv env args // Read a .NET instance field | [ I_ldfld (_alignment, _vol, _fspec); AI_nop ], _ -> - // permit byref for lhs lvalue of readonly value + // permit byref for lhs lvalue of readonly value CheckExprsPermitByRefLike cenv env args | [ I_ldsflda fspec ], [] -> @@ -1676,56 +1676,56 @@ and CheckExprOp cenv env (op, tyargs, args, m) ctxt expr = | [ I_ldelema (_, isNativePtr, _, _) ], lhsArray :: indices -> if ctxt.Disallow && cenv.reportErrors && not isNativePtr && isByrefLikeTy g m (tyOfExpr g expr) then errorR(Error(FSComp.SR.chkNoAddressOfArrayElementAtThisPoint(), m)) - // permit byref for lhs lvalue + // permit byref for lhs lvalue let limit = CheckExprPermitByRefLike cenv env lhsArray CheckExprsNoByRefLike cenv env indices |> ignore limit | [ AI_conv _ ], _ -> - // permit byref for args to conv - CheckExprsPermitByRefLike cenv env args + // permit byref for args to conv + CheckExprsPermitByRefLike cenv env args | _ -> - CheckExprsNoByRefLike cenv env args + CheckExprsNoByRefLike cenv env args | TOp.TraitCall _, _, _ -> CheckTypeInstNoByrefs cenv env m tyargs - // allow args to be byref here + // allow args to be byref here CheckExprsPermitByRefLike cenv env args - + | TOp.Recd _, _, _ -> CheckTypeInstNoByrefs cenv env m tyargs CheckExprsPermitByRefLike cenv env args - | _ -> + | _ -> CheckTypeInstNoByrefs cenv env m tyargs - CheckExprsNoByRefLike cenv env args + CheckExprsNoByRefLike cenv env args and CheckLambdas isTop (memberVal: Val option) cenv env inlined valReprInfo alwaysCheckNoReraise expr mOrig ety ctxt = let g = cenv.g let memInfo = memberVal |> Option.bind (fun v -> v.MemberInfo) - // The valReprInfo here says we are _guaranteeing_ to compile a function value - // as a .NET method with precisely the corresponding argument counts. + // The valReprInfo here says we are _guaranteeing_ to compile a function value + // as a .NET method with precisely the corresponding argument counts. match stripDebugPoints expr with - | Expr.TyChoose (tps, e1, m) -> + | Expr.TyChoose (tps, e1, m) -> let env = BindTypars g env tps CheckLambdas isTop memberVal cenv env inlined valReprInfo alwaysCheckNoReraise e1 m ety ctxt - | Expr.Lambda (_, _, _, _, _, m, _) + | Expr.Lambda (_, _, _, _, _, m, _) | Expr.TyLambda (_, _, _, m, _) -> let tps, ctorThisValOpt, baseValOpt, vsl, body, bodyTy = destLambdaWithValReprInfo g cenv.amap valReprInfo (expr, ety) - let env = BindTypars g env tps + let env = BindTypars g env tps let thisAndBase = Option.toList ctorThisValOpt @ Option.toList baseValOpt let restArgs = List.concat vsl let syntacticArgs = thisAndBase @ restArgs let env = BindArgVals env restArgs - match memInfo with + match memInfo with | None -> () - | Some mi -> + | Some mi -> // ctorThis and baseVal values are always considered used - for v in thisAndBase do v.SetHasBeenReferenced() + for v in thisAndBase do v.SetHasBeenReferenced() // instance method 'this' is always considered used match mi.MemberFlags.IsInstance, restArgs with | true, firstArg :: _ -> firstArg.SetHasBeenReferenced() @@ -1743,10 +1743,10 @@ and CheckLambdas isTop (memberVal: Val option) cenv env inlined valReprInfo alwa // Check argument types for arg in syntacticArgs do - if arg.InlineIfLambda && (not inlined || not (isFunTy g arg.Type || isFSharpDelegateTy g arg.Type)) then + if arg.InlineIfLambda && (not inlined || not (isFunTy g arg.Type || isFSharpDelegateTy g arg.Type)) then errorR(Error(FSComp.SR.tcInlineIfLambdaUsedOnNonInlineFunctionOrMethod(), arg.Range)) - CheckValSpecAux permitByRefType cenv env arg (fun () -> + CheckValSpecAux permitByRefType cenv env arg (fun () -> if arg.IsCompilerGenerated then errorR(Error(FSComp.SR.chkErrorUseOfByref(), arg.Range)) else @@ -1765,7 +1765,7 @@ and CheckLambdas isTop (memberVal: Val option) cenv env inlined valReprInfo alwa let freesOpt = CheckEscapes cenv memInfo.IsSome m syntacticArgs body // no reraise under lambda expression - CheckNoReraise cenv freesOpt body + CheckNoReraise cenv freesOpt body // Check the body of the lambda if isTop && not g.compilingFSharpCore && isByrefLikeTy g m bodyTy then @@ -1775,83 +1775,83 @@ and CheckLambdas isTop (memberVal: Val option) cenv env inlined valReprInfo alwa CheckExprNoByrefs cenv env body // Check byref return types - if cenv.reportErrors then + if cenv.reportErrors then if not isTop then - CheckForByrefLikeType cenv env m bodyTy (fun () -> + CheckForByrefLikeType cenv env m bodyTy (fun () -> errorR(Error(FSComp.SR.chkFirstClassFuncNoByref(), m))) - elif not g.compilingFSharpCore && isByrefTy g bodyTy then + elif not g.compilingFSharpCore && isByrefTy g bodyTy then // check no byrefs-in-the-byref - CheckForByrefType cenv env (destByrefTy g bodyTy) (fun () -> + CheckForByrefType cenv env (destByrefTy g bodyTy) (fun () -> errorR(Error(FSComp.SR.chkReturnTypeNoByref(), m))) - for tp in tps do - if tp.Constraints |> List.sumBy (function TyparConstraint.CoercesTo(ty, _) when isClassTy g ty -> 1 | _ -> 0) > 1 then + for tp in tps do + if tp.Constraints |> List.sumBy (function TyparConstraint.CoercesTo(ty, _) when isClassTy g ty -> 1 | _ -> 0) > 1 then errorR(Error(FSComp.SR.chkTyparMultipleClassConstraints(), m)) NoLimit - + // This path is for expression bindings that are not actually lambdas - | _ -> + | _ -> let m = mOrig // Permit byrefs for let x = ... CheckTypeNoInnerByrefs cenv env m ety - let limit = + let limit = if not inlined && (isByrefLikeTy g m ety || isNativePtrTy g ety) then - // allow byref to occur as RHS of byref binding. + // allow byref to occur as RHS of byref binding. CheckExpr cenv env expr ctxt - else + else CheckExprNoByrefs cenv env expr NoLimit - if alwaysCheckNoReraise then + if alwaysCheckNoReraise then CheckNoReraise cenv None expr limit and CheckExprs cenv env exprs ctxts : Limit = - let ctxts = Array.ofList ctxts - let argArity i = if i < ctxts.Length then ctxts[i] else PermitByRefExpr.No - exprs - |> List.mapi (fun i exp -> CheckExpr cenv env exp (argArity i)) + let ctxts = Array.ofList ctxts + let argArity i = if i < ctxts.Length then ctxts[i] else PermitByRefExpr.No + exprs + |> List.mapi (fun i exp -> CheckExpr cenv env exp (argArity i)) |> CombineLimits -and CheckExprsNoByRefLike cenv env exprs : Limit = +and CheckExprsNoByRefLike cenv env exprs : Limit = for expr in exprs do CheckExprNoByrefs cenv env expr NoLimit -and CheckExprsPermitByRefLike cenv env exprs : Limit = - exprs +and CheckExprsPermitByRefLike cenv env exprs : Limit = + exprs |> List.map (CheckExprPermitByRefLike cenv env) |> CombineLimits -and CheckExprPermitByRefLike cenv env expr : Limit = +and CheckExprPermitByRefLike cenv env expr : Limit = CheckExpr cenv env expr PermitByRefExpr.Yes -and CheckExprPermitReturnableByRef cenv env expr : Limit = +and CheckExprPermitReturnableByRef cenv env expr : Limit = CheckExpr cenv env expr PermitByRefExpr.YesReturnable -and CheckDecisionTreeTargets cenv env targets ctxt = - targets - |> Array.map (CheckDecisionTreeTarget cenv env ctxt) +and CheckDecisionTreeTargets cenv env targets ctxt = + targets + |> Array.map (CheckDecisionTreeTarget cenv env ctxt) |> List.ofArray |> CombineLimits -and CheckDecisionTreeTarget cenv env ctxt (TTarget(vs, targetExpr, _)) = - BindVals cenv env vs +and CheckDecisionTreeTarget cenv env ctxt (TTarget(vs, targetExpr, _)) = + BindVals cenv env vs for v in vs do CheckValSpec PermitByRefType.All cenv env v - CheckExpr cenv env targetExpr ctxt + CheckExpr cenv env targetExpr ctxt and CheckDecisionTree cenv env dtree = - match dtree with - | TDSuccess (resultExprs, _) -> + match dtree with + | TDSuccess (resultExprs, _) -> CheckExprsNoByRefLike cenv env resultExprs |> ignore - | TDBind(bind, rest) -> + | TDBind(bind, rest) -> CheckBinding cenv env false PermitByRefExpr.Yes bind |> ignore - CheckDecisionTree cenv env rest - | TDSwitch (inpExpr, cases, dflt, m) -> + CheckDecisionTree cenv env rest + | TDSwitch (inpExpr, cases, dflt, m) -> CheckDecisionTreeSwitch cenv env (inpExpr, cases, dflt, m) and CheckDecisionTreeSwitch cenv env (inpExpr, cases, dflt, m) = @@ -1859,7 +1859,7 @@ and CheckDecisionTreeSwitch cenv env (inpExpr, cases, dflt, m) = for (TCase(discrim, dtree)) in cases do CheckDecisionTreeTest cenv env m discrim CheckDecisionTree cenv env dtree - dflt |> Option.iter (CheckDecisionTree cenv env) + dflt |> Option.iter (CheckDecisionTree cenv env) and CheckDecisionTreeTest cenv env m discrim = match discrim with @@ -1877,25 +1877,25 @@ and CheckAttrib cenv env (Attrib(tcref, _, args, props, _, _, m)) = props |> List.iter (fun (AttribNamedArg(_, _, _, expr)) -> CheckAttribExpr cenv env expr) args |> List.iter (CheckAttribExpr cenv env) -and CheckAttribExpr cenv env (AttribExpr(expr, vexpr)) = +and CheckAttribExpr cenv env (AttribExpr(expr, vexpr)) = CheckExprNoByrefs cenv env expr CheckExprNoByrefs cenv env vexpr - CheckNoReraise cenv None expr + CheckNoReraise cenv None expr CheckAttribArgExpr cenv env vexpr -and CheckAttribArgExpr cenv env expr = +and CheckAttribArgExpr cenv env expr = let g = cenv.g - match expr with + match expr with - // Detect standard constants - | Expr.Const (c, m, _) -> - match c with - | Const.Bool _ - | Const.Int32 _ + // Detect standard constants + | Expr.Const (c, m, _) -> + match c with + | Const.Bool _ + | Const.Int32 _ | Const.SByte _ | Const.Int16 _ | Const.Int32 _ - | Const.Int64 _ + | Const.Int64 _ | Const.Byte _ | Const.UInt16 _ | Const.UInt32 _ @@ -1905,56 +1905,56 @@ and CheckAttribArgExpr cenv env expr = | Const.Char _ | Const.Zero | Const.String _ -> () - | _ -> - if cenv.reportErrors then + | _ -> + if cenv.reportErrors then errorR (Error (FSComp.SR.tastNotAConstantExpression(), m)) - - | Expr.Op (TOp.Array, [_elemTy], args, _m) -> + + | Expr.Op (TOp.Array, [_elemTy], args, _m) -> List.iter (CheckAttribArgExpr cenv env) args - | TypeOfExpr g _ -> + | TypeOfExpr g _ -> () - | TypeDefOfExpr g _ -> + | TypeDefOfExpr g _ -> () - | Expr.Op (TOp.Coerce, _, [arg], _) -> + | Expr.Op (TOp.Coerce, _, [arg], _) -> CheckAttribArgExpr cenv env arg - | EnumExpr g arg1 -> + | EnumExpr g arg1 -> CheckAttribArgExpr cenv env arg1 | AttribBitwiseOrExpr g (arg1, arg2) -> CheckAttribArgExpr cenv env arg1 CheckAttribArgExpr cenv env arg2 - | _ -> - if cenv.reportErrors then + | _ -> + if cenv.reportErrors then errorR (Error (FSComp.SR.chkInvalidCustAttrVal(), expr.Range)) - -and CheckAttribs cenv env (attribs: Attribs) = + +and CheckAttribs cenv env (attribs: Attribs) = if isNil attribs then () else let tcrefs = [ for Attrib(tcref, _, _, _, gs, _, m) in attribs -> (tcref, gs, m) ] // Check for violations of allowMultiple = false - let duplicates = + let duplicates = tcrefs |> Seq.groupBy (fun (tcref, gs, _) -> // Don't allow CompiledNameAttribute on both a property and its getter/setter (see E_CompiledName test) if tyconRefEq cenv.g cenv.g.attrib_CompiledNameAttribute.TyconRef tcref then (tcref.Stamp, false) else - (tcref.Stamp, gs)) - |> Seq.map (fun (_, elems) -> List.last (List.ofSeq elems), Seq.length elems) - |> Seq.filter (fun (_, count) -> count > 1) - |> Seq.map fst + (tcref.Stamp, gs)) + |> Seq.map (fun (_, elems) -> List.last (List.ofSeq elems), Seq.length elems) + |> Seq.filter (fun (_, count) -> count > 1) + |> Seq.map fst |> Seq.toList // Filter for allowMultiple = false |> List.filter (fun (tcref, _, m) -> TryFindAttributeUsageAttribute cenv.g m tcref <> Some true) - if cenv.reportErrors then + if cenv.reportErrors then for tcref, _, m in duplicates do errorR(Error(FSComp.SR.chkAttrHasAllowMultiFalse(tcref.DisplayName), m)) - - attribs |> List.iter (CheckAttrib cenv env) + + attribs |> List.iter (CheckAttrib cenv env) and CheckValInfo cenv env (ValReprInfo(_, args, ret)) = args |> List.iterSquared (CheckArgInfo cenv env) ret |> CheckArgInfo cenv env -and CheckArgInfo cenv env (argInfo : ArgReprInfo) = +and CheckArgInfo cenv env (argInfo : ArgReprInfo) = CheckAttribs cenv env argInfo.Attribs and CheckValSpecAux permitByRefLike cenv env (v: Val) onInnerByrefError = @@ -1966,12 +1966,12 @@ and CheckValSpec permitByRefLike cenv env v = CheckValSpecAux permitByRefLike cenv env v (fun () -> errorR(Error(FSComp.SR.chkErrorUseOfByref(), v.Range))) and AdjustAccess isHidden (cpath: unit -> CompilationPath) access = - if isHidden then + if isHidden then let (TAccess l) = access // FSharp 1.0 bug 1908: Values hidden by signatures are implicitly at least 'internal' let scoref = cpath().ILScopeRef TAccess(CompPath(scoref, []) :: l) - else + else access and CheckBinding cenv env alwaysCheckNoReraise ctxt (TBind(v, bindRhs, _) as bind) : Limit = @@ -1983,14 +1983,14 @@ and CheckBinding cenv env alwaysCheckNoReraise ctxt (TBind(v, bindRhs, _) as bin let env = { env with external = env.external || g.attrib_DllImportAttribute |> Option.exists (fun attr -> HasFSharpAttribute g attr v.Attribs) } // Check that active patterns don't have free type variables in their result - match TryGetActivePatternInfo vref with - | Some _apinfo when _apinfo.ActiveTags.Length > 1 -> + match TryGetActivePatternInfo vref with + | Some _apinfo when _apinfo.ActiveTags.Length > 1 -> if doesActivePatternHaveFreeTypars g vref then errorR(Error(FSComp.SR.activePatternChoiceHasFreeTypars(v.LogicalName), v.Range)) | _ -> () - + match cenv.potentialUnboundUsesOfVals.TryFind v.Stamp with - | None -> () + | None -> () | Some m -> let nm = v.DisplayName errorR(Error(FSComp.SR.chkMemberUsedInInvalidWay(nm, nm, stringOfRange m), v.Range)) @@ -2000,93 +2000,93 @@ and CheckBinding cenv env alwaysCheckNoReraise ctxt (TBind(v, bindRhs, _) as bin v.ValReprInfo |> Option.iter (CheckValInfo cenv env) // Check accessibility - if (v.IsMemberOrModuleBinding || v.IsMember) && not v.IsIncrClassGeneratedMember then + if (v.IsMemberOrModuleBinding || v.IsMember) && not v.IsIncrClassGeneratedMember then let access = AdjustAccess (IsHiddenVal env.sigToImplRemapInfo v) (fun () -> v.DeclaringEntity.CompilationPath) v.Accessibility CheckTypeForAccess cenv env (fun () -> NicePrint.stringOfQualifiedValOrMember cenv.denv cenv.infoReader vref) access v.Range v.Type - - if cenv.reportErrors then + + if cenv.reportErrors then // Check top-level let-bound values match bind.Var.ValReprInfo with - | Some info when info.HasNoArgs -> + | Some info when info.HasNoArgs -> CheckForByrefLikeType cenv env v.Range v.Type (fun () -> errorR(Error(FSComp.SR.chkNoByrefAsTopValue(), v.Range))) | _ -> () match v.PublicPath with | None -> () | _ -> - if + if // Don't support implicit [] on generated members, except the implicit members // for 'let' bound functions in classes. (not v.IsCompilerGenerated || v.IsIncrClassGeneratedMember) && - + (// Check the attributes on any enclosing module - env.reflect || + env.reflect || // Check the attributes on the value HasFSharpAttribute g g.attrib_ReflectedDefinitionAttribute v.Attribs || - // Also check the enclosing type for members - for historical reasons, in the TAST member values + // Also check the enclosing type for members - for historical reasons, in the TAST member values // are stored in the entity that encloses the type, hence we will not have noticed the ReflectedDefinition // on the enclosing type at this point. - HasFSharpAttribute g g.attrib_ReflectedDefinitionAttribute v.DeclaringEntity.Attribs) then + HasFSharpAttribute g g.attrib_ReflectedDefinitionAttribute v.DeclaringEntity.Attribs) then if v.IsInstanceMember && v.MemberApparentEntity.IsStructOrEnumTycon then errorR(Error(FSComp.SR.chkNoReflectedDefinitionOnStructMember(), v.Range)) cenv.usesQuotations <- true - // If we've already recorded a definition then skip this - match v.ReflectedDefinition with + // If we've already recorded a definition then skip this + match v.ReflectedDefinition with | None -> v.SetValDefn bindRhs | Some _ -> () // Run the conversion process over the reflected definition to report any errors in the // front end rather than the back end. We currently re-run this during ilxgen.fs but there's - // no real need for that except that it helps us to bundle all reflected definitions up into + // no real need for that except that it helps us to bundle all reflected definitions up into // one blob for pickling to the binary format try - let qscope = QuotationTranslator.QuotationGenerationScope.Create (g, cenv.amap, cenv.viewCcu, cenv.tcVal, QuotationTranslator.IsReflectedDefinition.Yes) + let qscope = QuotationTranslator.QuotationGenerationScope.Create (g, cenv.amap, cenv.viewCcu, cenv.tcVal, QuotationTranslator.IsReflectedDefinition.Yes) let methName = v.CompiledName g.CompilerGlobalState QuotationTranslator.ConvReflectedDefinition qscope methName v bindRhs |> ignore - + let _, _, exprSplices = qscope.Close() - if not (isNil exprSplices) then + if not (isNil exprSplices) then errorR(Error(FSComp.SR.chkReflectedDefCantSplice(), v.Range)) - with - | QuotationTranslator.InvalidQuotedTerm e -> + with + | QuotationTranslator.InvalidQuotedTerm e -> errorR e - - match v.MemberInfo with - | Some memberInfo when not v.IsIncrClassGeneratedMember -> - match memberInfo.MemberFlags.MemberKind with + + match v.MemberInfo with + | Some memberInfo when not v.IsIncrClassGeneratedMember -> + match memberInfo.MemberFlags.MemberKind with | SynMemberKind.PropertySet | SynMemberKind.PropertyGet -> // These routines raise errors for ill-formed properties v |> ReturnTypeOfPropertyVal g |> ignore v |> ArgInfosOfPropertyVal g |> ignore | _ -> () - + | _ -> () - - let valReprInfo = match bind.Var.ValReprInfo with Some info -> info | _ -> ValReprInfo.emptyValData + + let valReprInfo = match bind.Var.ValReprInfo with Some info -> info | _ -> ValReprInfo.emptyValData // If the method has ResumableCode argument or return type it must be inline // unless warning is suppressed (user must know what they're doing). // // If the method has ResumableCode return attribute we check the body w.r.t. that - let env = + let env = if cenv.reportErrors && isReturnsResumableCodeTy g v.TauType then if not (g.langVersion.SupportsFeature LanguageFeature.ResumableStateMachines) then error(Error(FSComp.SR.tcResumableCodeNotSupported(), bind.Var.Range)) - if not v.MustInline then + if not v.MustInline then warning(Error(FSComp.SR.tcResumableCodeFunctionMustBeInline(), v.Range)) - if isReturnsResumableCodeTy g v.TauType then - { env with resumableCode = Resumable.ResumableExpr false } + if isReturnsResumableCodeTy g v.TauType then + { env with resumableCode = Resumable.ResumableExpr false } else env CheckLambdas isTop (Some v) cenv env v.MustInline valReprInfo alwaysCheckNoReraise bindRhs v.Range v.Type ctxt -and CheckBindings cenv env binds = +and CheckBindings cenv env binds = for bind in binds do CheckBinding cenv env false PermitByRefExpr.Yes bind |> ignore @@ -2094,76 +2094,76 @@ and CheckBindings cenv env binds = let CheckModuleBinding cenv env (TBind(v, e, _) as bind) = let g = cenv.g let isExplicitEntryPoint = HasFSharpAttribute g g.attrib_EntryPointAttribute v.Attribs - if isExplicitEntryPoint then + if isExplicitEntryPoint then cenv.entryPointGiven <- true let isLastCompiland = fst cenv.isLastCompiland - if not isLastCompiland && cenv.reportErrors then - errorR(Error(FSComp.SR.chkEntryPointUsage(), v.Range)) + if not isLastCompiland && cenv.reportErrors then + errorR(Error(FSComp.SR.chkEntryPointUsage(), v.Range)) // Analyze the r.h.s. for the "IsCompiledAsStaticPropertyWithoutField" condition if // Mutable values always have fields - not v.IsMutable && + not v.IsMutable && // Literals always have fields - not (HasFSharpAttribute g g.attrib_LiteralAttribute v.Attribs) && - not (HasFSharpAttributeOpt g g.attrib_ThreadStaticAttribute v.Attribs) && - not (HasFSharpAttributeOpt g g.attrib_ContextStaticAttribute v.Attribs) && + not (HasFSharpAttribute g g.attrib_LiteralAttribute v.Attribs) && + not (HasFSharpAttributeOpt g g.attrib_ThreadStaticAttribute v.Attribs) && + not (HasFSharpAttributeOpt g g.attrib_ContextStaticAttribute v.Attribs) && // Having a field makes the binding a static initialization trigger - IsSimpleSyntacticConstantExpr g e && + IsSimpleSyntacticConstantExpr g e && // Check the thing is actually compiled as a property IsCompiledAsStaticProperty g v || (g.compilingFSharpCore && v.Attribs |> List.exists(fun (Attrib(tc, _, _, _, _, _, _)) -> tc.CompiledName = "ValueAsStaticPropertyAttribute")) - then + then v.SetIsCompiledAsStaticPropertyWithoutField() // Check for value name clashes begin - try + try // Skip compiler generated values if v.IsCompilerGenerated then () else // Skip explicit implementations of interface methods if ValIsExplicitImpl g v then () else - - match v.TryDeclaringEntity with + + match v.TryDeclaringEntity with | ParentNone -> () // this case can happen after error recovery from earlier error - | Parent _ -> - let tcref = v.DeclaringEntity - let hasDefaultAugmentation = + | Parent _ -> + let tcref = v.DeclaringEntity + let hasDefaultAugmentation = tcref.IsUnionTycon && match TryFindFSharpAttribute g g.attrib_DefaultAugmentationAttribute tcref.Attribs with | Some(Attrib(_, _, [ AttribBoolArg b ], _, _, _, _)) -> b | _ -> true (* not hiddenRepr *) let kind = (if v.IsMember then "member" else "value") - let check skipValCheck nm = - if not skipValCheck && - v.IsModuleBinding && - tcref.ModuleOrNamespaceType.AllValsByLogicalName.ContainsKey nm && + let check skipValCheck nm = + if not skipValCheck && + v.IsModuleBinding && + tcref.ModuleOrNamespaceType.AllValsByLogicalName.ContainsKey nm && not (valEq tcref.ModuleOrNamespaceType.AllValsByLogicalName[nm] v) then - + error(Duplicate(kind, v.DisplayName, v.Range)) #if CASES_IN_NESTED_CLASS - if tcref.IsUnionTycon && nm = "Cases" then + if tcref.IsUnionTycon && nm = "Cases" then errorR(NameClash(nm, kind, v.DisplayName, v.Range, "generated type", "Cases", tcref.Range)) #endif - if tcref.IsUnionTycon then - match nm with + if tcref.IsUnionTycon then + match nm with | "Tag" -> errorR(NameClash(nm, kind, v.DisplayName, v.Range, FSComp.SR.typeInfoGeneratedProperty(), "Tag", tcref.Range)) | "Tags" -> errorR(NameClash(nm, kind, v.DisplayName, v.Range, FSComp.SR.typeInfoGeneratedType(), "Tags", tcref.Range)) | _ -> - if hasDefaultAugmentation then - match tcref.GetUnionCaseByName nm with + if hasDefaultAugmentation then + match tcref.GetUnionCaseByName nm with | Some uc -> error(NameClash(nm, kind, v.DisplayName, v.Range, FSComp.SR.typeInfoUnionCase(), uc.DisplayName, uc.Range)) | None -> () - let hasNoArgs = - match v.ValReprInfo with - | None -> false + let hasNoArgs = + match v.ValReprInfo with + | None -> false | Some arity -> List.sum arity.AritiesOfArgs - v.NumObjArgs <= 0 && arity.NumTypars = 0 - // In unions user cannot define properties that clash with generated ones - if tcref.UnionCasesArray.Length = 1 && hasNoArgs then + // In unions user cannot define properties that clash with generated ones + if tcref.UnionCasesArray.Length = 1 && hasNoArgs then let ucase1 = tcref.UnionCasesArray[0] for f in ucase1.RecdFieldsArray do if f.LogicalName = nm then @@ -2172,18 +2172,18 @@ let CheckModuleBinding cenv env (TBind(v, e, _) as bind) = // Default augmentation contains the nasty 'Case' etc. let prefix = "New" if nm.StartsWithOrdinal prefix then - match tcref.GetUnionCaseByName(nm[prefix.Length ..]) with + match tcref.GetUnionCaseByName(nm[prefix.Length ..]) with | Some uc -> error(NameClash(nm, kind, v.DisplayName, v.Range, FSComp.SR.chkUnionCaseCompiledForm(), uc.DisplayName, uc.Range)) | None -> () // Default augmentation contains the nasty 'Is' etc. let prefix = "Is" if nm.StartsWithOrdinal prefix && hasDefaultAugmentation then - match tcref.GetUnionCaseByName(nm[prefix.Length ..]) with + match tcref.GetUnionCaseByName(nm[prefix.Length ..]) with | Some uc -> error(NameClash(nm, kind, v.DisplayName, v.Range, FSComp.SR.chkUnionCaseDefaultAugmentation(), uc.DisplayName, uc.Range)) | None -> () - match tcref.GetFieldByName nm with + match tcref.GetFieldByName nm with | Some rf -> error(NameClash(nm, kind, v.DisplayName, v.Range, "field", rf.LogicalName, rf.Range)) | None -> () @@ -2192,27 +2192,27 @@ let CheckModuleBinding cenv env (TBind(v, e, _) as bind) = check false (v.CompiledName cenv.g.CompilerGlobalState) // Check if an F# extension member clashes - if v.IsExtensionMember then - tcref.ModuleOrNamespaceType.AllValsAndMembersByLogicalNameUncached[v.LogicalName] |> List.iter (fun v2 -> + if v.IsExtensionMember then + tcref.ModuleOrNamespaceType.AllValsAndMembersByLogicalNameUncached[v.LogicalName] |> List.iter (fun v2 -> if v2.IsExtensionMember && not (valEq v v2) && (v.CompiledName cenv.g.CompilerGlobalState) = (v2.CompiledName cenv.g.CompilerGlobalState) then let minfo1 = FSMeth(g, generalizedTyconRef g tcref, mkLocalValRef v, Some 0UL) let minfo2 = FSMeth(g, generalizedTyconRef g tcref, mkLocalValRef v2, Some 0UL) - if tyconRefEq g v.MemberApparentEntity v2.MemberApparentEntity && - MethInfosEquivByNameAndSig EraseAll true g cenv.amap v.Range minfo1 minfo2 then + if tyconRefEq g v.MemberApparentEntity v2.MemberApparentEntity && + MethInfosEquivByNameAndSig EraseAll true g cenv.amap v.Range minfo1 minfo2 then errorR(Duplicate(kind, v.DisplayName, v.Range))) // Properties get 'get_X', only if there are no args // Properties get 'get_X' - match v.ValReprInfo with + match v.ValReprInfo with | Some arity when arity.NumCurriedArgs = 0 && arity.NumTypars = 0 -> check false ("get_" + v.DisplayName) | _ -> () - match v.ValReprInfo with + match v.ValReprInfo with | Some arity when v.IsMutable && arity.NumCurriedArgs = 0 && arity.NumTypars = 0 -> check false ("set_" + v.DisplayName) | _ -> () - match TryChopPropertyName v.DisplayName with - | Some res -> check true res + match TryChopPropertyName v.DisplayName with + | Some res -> check true res | None -> () - with e -> errorRecovery e v.Range + with e -> errorRecovery e v.Range end CheckBinding cenv { env with returnScope = 1 } true PermitByRefExpr.Yes bind |> ignore @@ -2221,26 +2221,26 @@ let CheckModuleBinding cenv env (TBind(v, e, _) as bind) = // check tycons //-------------------------------------------------------------------------- -let CheckRecdField isUnion cenv env (tycon: Tycon) (rfield: RecdField) = +let CheckRecdField isUnion cenv env (tycon: Tycon) (rfield: RecdField) = let g = cenv.g let tcref = mkLocalTyconRef tycon let m = rfield.Range let fieldTy = stripTyEqns cenv.g rfield.FormalType - let isHidden = - IsHiddenTycon env.sigToImplRemapInfo tycon || - IsHiddenTyconRepr env.sigToImplRemapInfo tycon || + let isHidden = + IsHiddenTycon env.sigToImplRemapInfo tycon || + IsHiddenTyconRepr env.sigToImplRemapInfo tycon || (not isUnion && IsHiddenRecdField env.sigToImplRemapInfo (tcref.MakeNestedRecdFieldRef rfield)) let access = AdjustAccess isHidden (fun () -> tycon.CompilationPath) rfield.Accessibility CheckTypeForAccess cenv env (fun () -> rfield.LogicalName) access m fieldTy - if isByrefLikeTyconRef g m tcref then + if isByrefLikeTyconRef g m tcref then // Permit Span fields in IsByRefLike types CheckTypePermitSpanLike cenv env m fieldTy if cenv.reportErrors then CheckForByrefType cenv env fieldTy (fun () -> errorR(Error(FSComp.SR.chkCantStoreByrefValue(), tycon.Range))) else CheckTypeNoByrefs cenv env m fieldTy - if cenv.reportErrors then + if cenv.reportErrors then CheckForByrefLikeType cenv env m fieldTy (fun () -> errorR(Error(FSComp.SR.chkCantStoreByrefValue(), tycon.Range))) CheckAttribs cenv env rfield.PropertyAttribs @@ -2251,7 +2251,7 @@ let CheckEntityDefn cenv env (tycon: Entity) = if tycon.IsProvidedGeneratedTycon then () else #endif let g = cenv.g - let m = tycon.Range + let m = tycon.Range let tcref = mkLocalTyconRef tycon let ty = generalizedTyconRef g tcref @@ -2268,9 +2268,9 @@ let CheckEntityDefn cenv env (tycon: Entity) = if not tycon.IsTypeAbbrev then - let allVirtualMethsInParent = - match GetSuperTypeOfType g cenv.amap m ty with - | Some superTy -> + let allVirtualMethsInParent = + match GetSuperTypeOfType g cenv.amap m ty with + | Some superTy -> GetIntrinsicMethInfosOfType cenv.infoReader None AccessibleFromSomewhere AllowMultiIntfInstantiations.Yes IgnoreOverrides m superTy |> List.filter (fun minfo -> minfo.IsVirtual) | None -> [] @@ -2282,7 +2282,7 @@ let CheckEntityDefn cenv env (tycon: Entity) = then MethInfosEquivByNameAndSig eraseFlag true g cenv.amap m minfo minfo2 else MethInfosEquivByNameAndPartialSig eraseFlag true g cenv.amap m minfo minfo2 (* partial ignores return type *) - let immediateMeths = + let immediateMeths = [ for v in tycon.AllGeneratedValues do yield FSMeth (g, ty, v, None) yield! GetImmediateIntrinsicMethInfosOfType (None, AccessibleFromSomewhere) g cenv.amap m ty ] @@ -2292,24 +2292,24 @@ let CheckEntityDefn cenv env (tycon: Entity) = match hash.TryGetValue nm with | true, h -> h | _ -> [] - + // precompute methods grouped by MethInfo.LogicalName - let hashOfImmediateMeths = + let hashOfImmediateMeths = let h = Dictionary() for minfo in immediateMeths do match h.TryGetValue minfo.LogicalName with - | true, methods -> + | true, methods -> h[minfo.LogicalName] <- minfo :: methods - | false, _ -> + | false, _ -> h[minfo.LogicalName] <- [minfo] h - let getOtherMethods (minfo : MethInfo) = + let getOtherMethods (minfo : MethInfo) = [ //we have added all methods to the dictionary on the previous step let methods = hashOfImmediateMeths[minfo.LogicalName] for m in methods do // use referential identity to filter out 'minfo' method - if not(Object.ReferenceEquals(m, minfo)) then + if not(Object.ReferenceEquals(m, minfo)) then yield m ] @@ -2319,34 +2319,34 @@ let CheckEntityDefn cenv env (tycon: Entity) = let m = (match minfo.ArbitraryValRef with None -> m | Some vref -> vref.DefinitionRange) let others = getOtherMethods minfo // abstract/default pairs of duplicate methods are OK - let IsAbstractDefaultPair (x: MethInfo) (y: MethInfo) = + let IsAbstractDefaultPair (x: MethInfo) (y: MethInfo) = x.IsDispatchSlot && y.IsDefiniteFSharpOverride - let IsAbstractDefaultPair2 (minfo: MethInfo) (minfo2: MethInfo) = + let IsAbstractDefaultPair2 (minfo: MethInfo) (minfo2: MethInfo) = IsAbstractDefaultPair minfo minfo2 || IsAbstractDefaultPair minfo2 minfo let checkForDup erasureFlag (minfo2: MethInfo) = not (IsAbstractDefaultPair2 minfo minfo2) && (minfo.IsInstance = minfo2.IsInstance) && MethInfosEquivWrtUniqueness erasureFlag m minfo minfo2 - if others |> List.exists (checkForDup EraseAll) then - if others |> List.exists (checkForDup EraseNone) then + if others |> List.exists (checkForDup EraseAll) then + if others |> List.exists (checkForDup EraseNone) then errorR(Error(FSComp.SR.chkDuplicateMethod(nm, NicePrint.minimalStringOfType cenv.denv ty), m)) else errorR(Error(FSComp.SR.chkDuplicateMethodWithSuffix(nm, NicePrint.minimalStringOfType cenv.denv ty), m)) let numCurriedArgSets = minfo.NumArgs.Length - if numCurriedArgSets > 1 && others |> List.exists (fun minfo2 -> not (IsAbstractDefaultPair2 minfo minfo2)) then + if numCurriedArgSets > 1 && others |> List.exists (fun minfo2 -> not (IsAbstractDefaultPair2 minfo minfo2)) then errorR(Error(FSComp.SR.chkDuplicateMethodCurried(nm, NicePrint.minimalStringOfType cenv.denv ty), m)) - if numCurriedArgSets > 1 && - (minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) - |> List.existsSquared (fun (ParamData(isParamArrayArg, _isInArg, isOutArg, optArgInfo, callerInfo, _, reflArgInfo, ty)) -> - isParamArrayArg || isOutArg || reflArgInfo.AutoQuote || optArgInfo.IsOptional || callerInfo <> NoCallerInfo || isByrefLikeTy g m ty)) then + if numCurriedArgSets > 1 && + (minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) + |> List.existsSquared (fun (ParamData(isParamArrayArg, _isInArg, isOutArg, optArgInfo, callerInfo, _, reflArgInfo, ty)) -> + isParamArrayArg || isOutArg || reflArgInfo.AutoQuote || optArgInfo.IsOptional || callerInfo <> NoCallerInfo || isByrefLikeTy g m ty)) then errorR(Error(FSComp.SR.chkCurriedMethodsCantHaveOutParams(), m)) if numCurriedArgSets = 1 then - minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) + minfo.GetParamDatas(cenv.amap, m, minfo.FormalMethodInst) |> List.iterSquared (fun (ParamData(_, isInArg, _, optArgInfo, callerInfo, _, _, ty)) -> ignore isInArg match (optArgInfo, callerInfo) with @@ -2370,46 +2370,46 @@ let CheckEntityDefn cenv env (tycon: Entity) = | CalleeSide, CallerMemberName -> if not ((isOptionTy g ty) && (typeEquiv g g.string_ty (destOptionTy g ty))) then errorR(Error(FSComp.SR.tcCallerInfoWrongType(callerInfo.ToString(), "string", NicePrint.minimalStringOfType cenv.denv (destOptionTy g ty)), m))) - + for pinfo in immediateProps do let nm = pinfo.PropertyName - let m = - match pinfo.ArbitraryValRef with - | None -> m + let m = + match pinfo.ArbitraryValRef with + | None -> m | Some vref -> vref.DefinitionRange - if hashOfImmediateMeths.ContainsKey nm then + if hashOfImmediateMeths.ContainsKey nm then errorR(Error(FSComp.SR.chkPropertySameNameMethod(nm, NicePrint.minimalStringOfType cenv.denv ty), m)) let others = getHash hashOfImmediateProps nm - if pinfo.HasGetter && pinfo.HasSetter && pinfo.GetterMethod.IsVirtual <> pinfo.SetterMethod.IsVirtual then + if pinfo.HasGetter && pinfo.HasSetter && pinfo.GetterMethod.IsVirtual <> pinfo.SetterMethod.IsVirtual then errorR(Error(FSComp.SR.chkGetterSetterDoNotMatchAbstract(nm, NicePrint.minimalStringOfType cenv.denv ty), m)) - let checkForDup erasureFlag pinfo2 = + let checkForDup erasureFlag pinfo2 = // abstract/default pairs of duplicate properties are OK - let IsAbstractDefaultPair (x: PropInfo) (y: PropInfo) = + let IsAbstractDefaultPair (x: PropInfo) (y: PropInfo) = x.IsDispatchSlot && y.IsDefiniteFSharpOverride not (IsAbstractDefaultPair pinfo pinfo2 || IsAbstractDefaultPair pinfo2 pinfo) && PropInfosEquivByNameAndPartialSig erasureFlag g cenv.amap m pinfo pinfo2 (* partial ignores return type *) if others |> List.exists (checkForDup EraseAll) then - if others |> List.exists (checkForDup EraseNone) then + if others |> List.exists (checkForDup EraseNone) then errorR(Error(FSComp.SR.chkDuplicateProperty(nm, NicePrint.minimalStringOfType cenv.denv ty), m)) else errorR(Error(FSComp.SR.chkDuplicatePropertyWithSuffix(nm, NicePrint.minimalStringOfType cenv.denv ty), m)) // Check to see if one is an indexer and one is not - if ( (pinfo.HasGetter && - pinfo.HasSetter && + if ( (pinfo.HasGetter && + pinfo.HasSetter && let setterArgs = pinfo.DropGetter().GetParamTypes(cenv.amap, m) let getterArgs = pinfo.DropSetter().GetParamTypes(cenv.amap, m) setterArgs.Length <> getterArgs.Length) - || + || (let nargs = pinfo.GetParamTypes(cenv.amap, m).Length - others |> List.exists (fun pinfo2 -> (isNil(pinfo2.GetParamTypes(cenv.amap, m))) <> (nargs = 0)))) then - + others |> List.exists (fun pinfo2 -> (isNil(pinfo2.GetParamTypes(cenv.amap, m))) <> (nargs = 0)))) then + errorR(Error(FSComp.SR.chkPropertySameNameIndexer(nm, NicePrint.minimalStringOfType cenv.denv ty), m)) // Check to see if the signatures of the both getter and the setter imply the same property type @@ -2421,7 +2421,7 @@ let CheckEntityDefn cenv env (tycon: Entity) = errorR(Error(FSComp.SR.chkGetterAndSetterHaveSamePropertyType(pinfo.PropertyName, NicePrint.minimalStringOfType cenv.denv ty1, NicePrint.minimalStringOfType cenv.denv ty2), m)) hashOfImmediateProps[nm] <- pinfo :: others - + if not (isInterfaceTy g ty) then let hashOfAllVirtualMethsInParent = Dictionary() for minfo in allVirtualMethsInParent do @@ -2432,192 +2432,192 @@ let CheckEntityDefn cenv env (tycon: Entity) = if not minfo.IsDispatchSlot && not minfo.IsVirtual && minfo.IsInstance then let nm = minfo.LogicalName let m = (match minfo.ArbitraryValRef with None -> m | Some vref -> vref.DefinitionRange) - let parentMethsOfSameName = getHash hashOfAllVirtualMethsInParent nm + let parentMethsOfSameName = getHash hashOfAllVirtualMethsInParent nm let checkForDup erasureFlag (minfo2: MethInfo) = minfo2.IsDispatchSlot && MethInfosEquivByNameAndSig erasureFlag true g cenv.amap m minfo minfo2 match parentMethsOfSameName |> List.tryFind (checkForDup EraseAll) with | None -> () | Some minfo -> let mtext = NicePrint.stringOfMethInfo cenv.infoReader m cenv.denv minfo - if parentMethsOfSameName |> List.exists (checkForDup EraseNone) then + if parentMethsOfSameName |> List.exists (checkForDup EraseNone) then warning(Error(FSComp.SR.tcNewMemberHidesAbstractMember mtext, m)) else warning(Error(FSComp.SR.tcNewMemberHidesAbstractMemberWithSuffix mtext, m)) - + if minfo.IsDispatchSlot then let nm = minfo.LogicalName let m = (match minfo.ArbitraryValRef with None -> m | Some vref -> vref.DefinitionRange) - let parentMethsOfSameName = getHash hashOfAllVirtualMethsInParent nm + let parentMethsOfSameName = getHash hashOfAllVirtualMethsInParent nm let checkForDup erasureFlag minfo2 = MethInfosEquivByNameAndSig erasureFlag true g cenv.amap m minfo minfo2 - + if parentMethsOfSameName |> List.exists (checkForDup EraseAll) then - if parentMethsOfSameName |> List.exists (checkForDup EraseNone) then + if parentMethsOfSameName |> List.exists (checkForDup EraseNone) then errorR(Error(FSComp.SR.chkDuplicateMethodInheritedType nm, m)) else errorR(Error(FSComp.SR.chkDuplicateMethodInheritedTypeWithSuffix nm, m)) - if TyconRefHasAttributeByName m tname_IsByRefLikeAttribute tcref && not tycon.IsStructOrEnumTycon then + if TyconRefHasAttributeByName m tname_IsByRefLikeAttribute tcref && not tycon.IsStructOrEnumTycon then errorR(Error(FSComp.SR.tcByRefLikeNotStruct(), tycon.Range)) - if TyconRefHasAttribute g m g.attrib_IsReadOnlyAttribute tcref && not tycon.IsStructOrEnumTycon then + if TyconRefHasAttribute g m g.attrib_IsReadOnlyAttribute tcref && not tycon.IsStructOrEnumTycon then errorR(Error(FSComp.SR.tcIsReadOnlyNotStruct(), tycon.Range)) - // Considers TFSharpObjectRepr, TFSharpRecdRepr and TFSharpUnionRepr. + // Considers TFSharpObjectRepr, TFSharpRecdRepr and TFSharpUnionRepr. // [Review] are all cases covered: TILObjectRepr, TAsmRepr. [Yes - these are FSharp.Core.dll only] tycon.AllFieldsArray |> Array.iter (CheckRecdField false cenv env tycon) - + // Abstract slots can have byref arguments and returns - for vref in abstractSlotValsOfTycons [tycon] do - match vref.ValReprInfo with - | Some valReprInfo -> + for vref in abstractSlotValsOfTycons [tycon] do + match vref.ValReprInfo with + | Some valReprInfo -> let tps, argTysl, retTy, _ = GetValReprTypeInFSharpForm g valReprInfo vref.Type m let env = BindTypars g env tps - for argTys in argTysl do - for argTy, _ in argTys do + for argTys in argTysl do + for argTy, _ in argTys do CheckTypeNoInnerByrefs cenv env vref.Range argTy CheckTypeNoInnerByrefs cenv env vref.Range retTy | None -> () // Supported interface may not have byrefs - tycon.ImmediateInterfaceTypesOfFSharpTycon |> List.iter (CheckTypeNoByrefs cenv env m) + tycon.ImmediateInterfaceTypesOfFSharpTycon |> List.iter (CheckTypeNoByrefs cenv env m) - superOfTycon g tycon |> CheckTypeNoByrefs cenv env m + superOfTycon g tycon |> CheckTypeNoByrefs cenv env m - if tycon.IsUnionTycon then + if tycon.IsUnionTycon then for ucase in tycon.UnionCasesArray do - CheckAttribs cenv env ucase.Attribs + CheckAttribs cenv env ucase.Attribs ucase.RecdFieldsArray |> Array.iter (CheckRecdField true cenv env tycon) // Access checks let access = AdjustAccess (IsHiddenTycon env.sigToImplRemapInfo tycon) (fun () -> tycon.CompilationPath) tycon.Accessibility - let visitType ty = CheckTypeForAccess cenv env (fun () -> tycon.DisplayNameWithStaticParametersAndUnderscoreTypars) access tycon.Range ty + let visitType ty = CheckTypeForAccess cenv env (fun () -> tycon.DisplayNameWithStaticParametersAndUnderscoreTypars) access tycon.Range ty - abstractSlotValsOfTycons [tycon] |> List.iter (typeOfVal >> visitType) + abstractSlotValsOfTycons [tycon] |> List.iter (typeOfVal >> visitType) superOfTycon g tycon |> visitType // We do not have to check access of interface implementations. - if tycon.IsFSharpDelegateTycon then - match tycon.TypeReprInfo with + if tycon.IsFSharpDelegateTycon then + match tycon.TypeReprInfo with | TFSharpObjectRepr r -> - match r.fsobjmodel_kind with + match r.fsobjmodel_kind with | TFSharpDelegate ss -> - //ss.ClassTypars - //ss.MethodTypars + //ss.ClassTypars + //ss.MethodTypars ss.FormalReturnType |> Option.iter visitType ss.FormalParams |> List.iterSquared (fun (TSlotParam(_, ty, _, _, _, _)) -> visitType ty) | _ -> () | _ -> () - let interfaces = + let interfaces = AllSuperTypesOfType g cenv.amap tycon.Range AllowMultiIntfInstantiations.Yes ty |> List.filter (isInterfaceTy g) - - if tycon.IsFSharpInterfaceTycon then + + if tycon.IsFSharpInterfaceTycon then List.iter visitType interfaces // Check inherited interface is as accessible if not (isRecdOrStructTyconRefAssumedImmutable g tcref) && isRecdOrStructTyconRefReadOnly g m tcref then errorR(Error(FSComp.SR.readOnlyAttributeOnStructWithMutableField(), m)) - - if cenv.reportErrors then - if not tycon.IsTypeAbbrev then + + if cenv.reportErrors then + if not tycon.IsTypeAbbrev then let interfaces = GetImmediateInterfacesOfType SkipUnrefInterfaces.Yes g cenv.amap m ty |> List.collect (AllSuperTypesOfType g cenv.amap m AllowMultiIntfInstantiations.Yes) |> List.filter (isInterfaceTy g) CheckMultipleInterfaceInstantiations cenv ty interfaces false m - + // Check fields. We check these late because we have to have first checked that the structs are // free of cycles - if tycon.IsStructOrEnumTycon then + if tycon.IsStructOrEnumTycon then for f in tycon.AllInstanceFieldsAsList do - // Check if it's marked unsafe + // Check if it's marked unsafe let zeroInitUnsafe = TryFindFSharpBoolAttribute g g.attrib_DefaultValueAttribute f.FieldAttribs if zeroInitUnsafe = Some true then - if not (TypeHasDefaultValue g m ty) then + if not (TypeHasDefaultValue g m ty) then errorR(Error(FSComp.SR.chkValueWithDefaultValueMustHaveDefaultValue(), m)) // Check type abbreviations - match tycon.TypeAbbrev with + match tycon.TypeAbbrev with | None -> () - | Some ty -> + | Some ty -> // Library-defined outref<'T> and inref<'T> contain byrefs on the r.h.s. - if not g.compilingFSharpCore then + if not g.compilingFSharpCore then CheckForByrefType cenv env ty (fun () -> errorR(Error(FSComp.SR.chkNoByrefInTypeAbbrev(), tycon.Range))) -let CheckEntityDefns cenv env tycons = - tycons |> List.iter (CheckEntityDefn cenv env) +let CheckEntityDefns cenv env tycons = + tycons |> List.iter (CheckEntityDefn cenv env) //-------------------------------------------------------------------------- // check modules //-------------------------------------------------------------------------- -let rec CheckDefnsInModule cenv env mdefs = +let rec CheckDefnsInModule cenv env mdefs = for mdef in mdefs do CheckDefnInModule cenv env mdef and CheckNothingAfterEntryPoint cenv m = - if cenv.entryPointGiven && cenv.reportErrors then - errorR(Error(FSComp.SR.chkEntryPointUsage(), m)) + if cenv.entryPointGiven && cenv.reportErrors then + errorR(Error(FSComp.SR.chkEntryPointUsage(), m)) -and CheckDefnInModule cenv env mdef = - match mdef with - | TMDefRec(isRec, _opens, tycons, mspecs, m) -> +and CheckDefnInModule cenv env mdef = + match mdef with + | TMDefRec(isRec, _opens, tycons, mspecs, m) -> CheckNothingAfterEntryPoint cenv m if isRec then BindVals cenv env (allValsOfModDef mdef |> Seq.toList) CheckEntityDefns cenv env tycons List.iter (CheckModuleSpec cenv env) mspecs - | TMDefLet(bind, m) -> + | TMDefLet(bind, m) -> CheckNothingAfterEntryPoint cenv m - CheckModuleBinding cenv env bind + CheckModuleBinding cenv env bind BindVal cenv env bind.Var | TMDefOpens _ -> () - | TMDefDo(e, m) -> + | TMDefDo(e, m) -> CheckNothingAfterEntryPoint cenv m CheckNoReraise cenv None e CheckExprNoByrefs cenv env e - | TMDefs defs -> CheckDefnsInModule cenv env defs + | TMDefs defs -> CheckDefnsInModule cenv env defs and CheckModuleSpec cenv env mbind = - match mbind with + match mbind with | ModuleOrNamespaceBinding.Binding bind -> BindVals cenv env (valsOfBinds [bind]) CheckModuleBinding cenv env bind | ModuleOrNamespaceBinding.Module (mspec, rhs) -> CheckEntityDefn cenv env mspec let env = { env with reflect = env.reflect || HasFSharpAttribute cenv.g cenv.g.attrib_ReflectedDefinitionAttribute mspec.Attribs } - CheckDefnInModule cenv env rhs + CheckDefnInModule cenv env rhs -let CheckImplFileContents cenv env implFileTy implFileContents = +let CheckImplFileContents cenv env implFileTy implFileContents = let rpi, mhi = ComputeRemappingFromImplementationToSignature cenv.g implFileContents implFileTy let env = { env with sigToImplRemapInfo = (mkRepackageRemapping rpi, mhi) :: env.sigToImplRemapInfo } UpdatePrettyTyparNames.updateModuleOrNamespaceType implFileTy CheckDefnInModule cenv env implFileContents - + let CheckImplFile (g, amap, reportErrors, infoReader, internalsVisibleToPaths, viewCcu, tcValF, denv, implFileTy, implFileContents, extraAttribs, isLastCompiland: bool*bool, isInternalTestSpanStackReferring) = - let cenv = - { g = g - reportErrors = reportErrors - boundVals = Dictionary<_, _>(100, HashIdentity.Structural) - limitVals = Dictionary<_, _>(100, HashIdentity.Structural) + let cenv = + { g = g + reportErrors = reportErrors + boundVals = Dictionary<_, _>(100, HashIdentity.Structural) + limitVals = Dictionary<_, _>(100, HashIdentity.Structural) stackGuard = StackGuard(PostInferenceChecksStackGuardDepth, "CheckImplFile") - potentialUnboundUsesOfVals = Map.empty + potentialUnboundUsesOfVals = Map.empty anonRecdTypes = StampMap.Empty - usesQuotations = false - infoReader = infoReader + usesQuotations = false + infoReader = infoReader internalsVisibleToPaths = internalsVisibleToPaths - amap = amap - denv = denv + amap = amap + denv = denv viewCcu = viewCcu isLastCompiland = isLastCompiland isInternalTestSpanStackReferring = isInternalTestSpanStackReferring tcVal = tcValF entryPointGiven = false} - + // Certain type equality checks go faster if these TyconRefs are pre-resolved. // This is because pre-resolving allows tycon equality to be determined by pointer equality on the entities. // See primEntityRefEq. @@ -2629,14 +2629,14 @@ let CheckImplFile (g, amap, reportErrors, infoReader, internalsVisibleToPaths, v resolve g.system_ArgIterator_tcref resolve g.system_RuntimeArgumentHandle_tcref - let env = + let env = { sigToImplRemapInfo=[] quote=false boundTyparNames=[] argVals = ValMap.Empty boundTypars= TyparMap.Empty reflect=false - external=false + external=false returnScope = 0 isInAppExpr = false resumableCode = Resumable.None } @@ -2644,7 +2644,7 @@ let CheckImplFile (g, amap, reportErrors, infoReader, internalsVisibleToPaths, v CheckImplFileContents cenv env implFileTy implFileContents CheckAttribs cenv env extraAttribs - if cenv.usesQuotations && not (QuotationTranslator.QuotationGenerationScope.ComputeQuotationFormat(g).SupportsDeserializeEx) then + if cenv.usesQuotations && not (QuotationTranslator.QuotationGenerationScope.ComputeQuotationFormat(g).SupportsDeserializeEx) then viewCcu.UsesFSharp20PlusQuotations <- true cenv.entryPointGiven, cenv.anonRecdTypes From 4b4e365a1b95b7e89c594997b516dd66892557cf Mon Sep 17 00:00:00 2001 From: Adam Boniecki Date: Tue, 4 Jul 2023 17:33:53 +0200 Subject: [PATCH 5/7] Replace stamp with fixed name for IL gen --- src/Compiler/TypedTree/TypedTree.fs | 2 +- src/Compiler/TypedTree/TypedTreePickle.fs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index bad04d71c0f..17f10d3b82a 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -4298,7 +4298,7 @@ type AnonRecdTypeInfo = /// Get the ILTypeRef for the generated type implied by the anonymous type member x.ILTypeRef = - let ilTypeName = sprintf "<>f__AnonymousType%s%u`%d" (match x.TupInfo with TupInfo.Const b -> if b then "1000" else "") (uint32 x.Stamp) x.SortedIds.Length + let ilTypeName = sprintf "<>f__AnonymousType%s%u`%d" (match x.TupInfo with TupInfo.Const b -> if b then "1000" else "") (uint32 x.IlTypeName) x.SortedIds.Length mkILTyRef(x.Assembly.ILScopeRef, ilTypeName) static member NewUnlinked() : AnonRecdTypeInfo = diff --git a/src/Compiler/TypedTree/TypedTreePickle.fs b/src/Compiler/TypedTree/TypedTreePickle.fs index f7f98e5620b..0dfeef86d94 100644 --- a/src/Compiler/TypedTree/TypedTreePickle.fs +++ b/src/Compiler/TypedTree/TypedTreePickle.fs @@ -701,7 +701,7 @@ let pickleObjWithDanglingCcus inMem file g scope p x = oentities=NodeOutTable<_, _>.Create((fun (tc: Tycon) -> tc.Stamp), (fun tc -> tc.LogicalName), (fun tc -> tc.Range), id , "otycons") otypars=NodeOutTable<_, _>.Create((fun (tp: Typar) -> tp.Stamp), (fun tp -> tp.DisplayName), (fun tp -> tp.Range), id , "otypars") ovals=NodeOutTable<_, _>.Create((fun (v: Val) -> v.Stamp), (fun v -> v.LogicalName), (fun v -> v.Range), id , "ovals") - oanoninfos=NodeOutTable<_, _>.Create((fun (v: AnonRecdTypeInfo) -> v.Stamp), (fun v -> string v.Stamp), (fun _ -> range0), id, "oanoninfos") + oanoninfos=NodeOutTable<_, _>.Create((fun (v: AnonRecdTypeInfo) -> v.Stamp), (fun v -> string v.IlTypeName), (fun _ -> range0), id, "oanoninfos") ostrings=Table<_>.Create "ostrings" onlerefs=Table<_>.Create "onlerefs" opubpaths=Table<_>.Create "opubpaths" @@ -726,7 +726,7 @@ let pickleObjWithDanglingCcus inMem file g scope p x = oentities=NodeOutTable<_, _>.Create((fun (tc: Tycon) -> tc.Stamp), (fun tc -> tc.LogicalName), (fun tc -> tc.Range), id , "otycons") otypars=NodeOutTable<_, _>.Create((fun (tp: Typar) -> tp.Stamp), (fun tp -> tp.DisplayName), (fun tp -> tp.Range), id , "otypars") ovals=NodeOutTable<_, _>.Create((fun (v: Val) -> v.Stamp), (fun v -> v.LogicalName), (fun v -> v.Range), (fun osgn -> osgn), "ovals") - oanoninfos=NodeOutTable<_, _>.Create((fun (v: AnonRecdTypeInfo) -> v.Stamp), (fun v -> string v.Stamp), (fun _ -> range0), id, "oanoninfos") + oanoninfos=NodeOutTable<_, _>.Create((fun (v: AnonRecdTypeInfo) -> v.Stamp), (fun v -> string v.IlTypeName), (fun _ -> range0), id, "oanoninfos") ostrings=Table<_>.Create "ostrings (fake)" opubpaths=Table<_>.Create "opubpaths (fake)" onlerefs=Table<_>.Create "onlerefs (fake)" From 47658f2959d3ac3465cb123b429cb4453147c1a2 Mon Sep 17 00:00:00 2001 From: Adam Boniecki Date: Tue, 11 Jul 2023 14:44:07 +0200 Subject: [PATCH 6/7] Fix instantiation of AnonRecdTypeInfo New property (IlTypeName) needs to be set on creation --- src/Compiler/TypedTree/TypedTree.fs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index 17f10d3b82a..6d06a608303 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -4316,6 +4316,7 @@ type AnonRecdTypeInfo = x.SortedIds <- d.SortedIds x.Stamp <- d.Stamp x.SortedNames <- sortedNames + x.IlTypeName <- d.IlTypeName member x.IsLinked = (match x.SortedIds with null -> true | _ -> false) From b86e3ee45228c158835260fb4e8549055d8aad7a Mon Sep 17 00:00:00 2001 From: Adam Boniecki Date: Tue, 11 Jul 2023 15:58:09 +0200 Subject: [PATCH 7/7] Comment on not changing generated IL type name --- src/Compiler/TypedTree/TypedTree.fs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index 6d06a608303..058cce5866c 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -4275,7 +4275,10 @@ type AnonRecdTypeInfo = /// Create an AnonRecdTypeInfo from the basic data static member Create(ccu: CcuThunk, tupInfo, ids: Ident[]) = let sortedIds = ids |> Array.sortBy (fun id -> id.idText) - // Hash all the data to form a unique stamp + + // Hash all the data to form a unique stamp. + // This used to be used as an input for generating IL type name, however the stamp generation + // had to be modified to fix #6411, and the IL type name must remain unchanged for back compat reasons. let stamp = sha1HashInt64 [| for c in ccu.AssemblyName do yield byte c; yield byte (int32 c >>> 8) @@ -4285,6 +4288,8 @@ type AnonRecdTypeInfo = for c in id.idText do yield byte c; yield byte (int32 c >>> 8) yield 0uy |] + // Hash data to form a code used in generating IL type name. + // To maintain backward compatibility this should not be changed. let ilName = sha1HashInt64 [| for c in ccu.AssemblyName do yield byte c; yield byte (int32 c >>> 8)