Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge main to feature/nullness #16679

Merged
merged 9 commits into from
Feb 9, 2024
2 changes: 2 additions & 0 deletions docs/release-notes/.FSharp.Compiler.Service/8.0.300.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
* Code generated files with > 64K methods and generated symbols crash when loaded. Use infered sequence points for debugging. ([Issue #16399](https://github.com/dotnet/fsharp/issues/16399), [#PR 16514](https://github.com/dotnet/fsharp/pull/16514))
* `nameof Module` expressions and patterns are processed to link files in `--test:GraphBasedChecking`. ([PR #16550](https://github.com/dotnet/fsharp/pull/16550))
* Graph Based Checking doesn't throw on invalid parsed input so it can be used for IDE scenarios ([PR #16575](https://github.com/dotnet/fsharp/pull/16575), [PR #16588](https://github.com/dotnet/fsharp/pull/16588), [PR #16643](https://github.com/dotnet/fsharp/pull/16643))
* Various parenthesization API fixes. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578), [PR #16666](https://github.com/dotnet/fsharp/pull/16666))
* Keep parens for problematic exprs (`if`, `match`, etc.) in `$"{(…):N0}"`, `$"{(…),-3}"`, etc. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578))
* Fix crash in DOTNET_SYSTEM_GLOBALIZATION_INVARIANT mode ([PR #16471](https://github.com/dotnet/fsharp/pull/16471))
* `[<CliEvent>]` member should not produce property symbol. ([Issue #16640](https://github.com/dotnet/fsharp/issues/16640), [PR #16658](https://github.com/dotnet/fsharp/pull/16658))
* Fix discriminated union initialization. ([#PR 16661](https://github.com/dotnet/fsharp/pull/16661))

### Added

Expand Down
1 change: 1 addition & 0 deletions docs/release-notes/.VisualStudio/17.10.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
### Fixed

* Show signature help mid-pipeline in more scenarios. ([PR #16462](https://github.com/dotnet/fsharp/pull/16462))
* Various unneeded parentheses code fix improvements. ([PR #16578](https://github.com/dotnet/fsharp/pull/16578), [PR #16666](https://github.com/dotnet/fsharp/pull/16666))

### Changed

Expand Down
26 changes: 26 additions & 0 deletions src/Compiler/AbstractIL/il.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3952,6 +3952,29 @@ let mdef_code2code f (md: ILMethodDef) =
let b = MethodBody.IL(notlazy ilCode)
md.With(body = notlazy b)

let appendInstrsToCode (instrs: ILInstr list) (c2: ILCode) =
let instrs = Array.ofList instrs

match
c2.Instrs
|> Array.tryFindIndexBack (fun instr ->
match instr with
| I_ret -> true
| _ -> false)
with
| Some 0 ->
{ c2 with
Instrs = Array.concat [| instrs; c2.Instrs |]
}
| Some index ->
{ c2 with
Instrs = Array.concat [| c2.Instrs[.. index - 1]; instrs; c2.Instrs[index..] |]
}
| None ->
{ c2 with
Instrs = Array.append c2.Instrs instrs
}

let prependInstrsToCode (instrs: ILInstr list) (c2: ILCode) =
let instrs = Array.ofList instrs
let n = instrs.Length
Expand Down Expand Up @@ -3985,6 +4008,9 @@ let prependInstrsToCode (instrs: ILInstr list) (c2: ILCode) =
Instrs = Array.append instrs c2.Instrs
}

let appendInstrsToMethod newCode md =
mdef_code2code (appendInstrsToCode newCode) md

let prependInstrsToMethod newCode md =
mdef_code2code (prependInstrsToCode newCode) md

Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/AbstractIL/il.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -2162,8 +2162,9 @@ val internal mkRawDataValueTypeDef: ILType -> string * size: int32 * pack: uint1
/// the code, and the first instruction will be the new entry
/// of the method. The instructions should be non-branching.

val internal appendInstrsToCode: ILInstr list -> ILCode -> ILCode
val internal appendInstrsToMethod: ILInstr list -> ILMethodDef -> ILMethodDef
val internal prependInstrsToCode: ILInstr list -> ILCode -> ILCode

val internal prependInstrsToMethod: ILInstr list -> ILMethodDef -> ILMethodDef

/// Injecting initialization code into a class.
Expand Down
80 changes: 45 additions & 35 deletions src/Compiler/CodeGen/IlxGen.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1908,7 +1908,16 @@ type TypeDefBuilder(tdef: ILTypeDef, tdefDiscards) =
if not discard then
AddPropertyDefToHash m gproperties pdef

member _.PrependInstructionsToSpecificMethodDef(cond, instrs, tag, imports) =
member _.AppendInstructionsToSpecificMethodDef(cond, instrs, tag, imports) =
match ResizeArray.tryFindIndex cond gmethods with
| Some idx -> gmethods[idx] <- appendInstrsToMethod instrs gmethods[idx]
| None ->
let body =
mkMethodBody (false, [], 1, nonBranchingInstrsToCode instrs, tag, imports)

gmethods.Add(mkILClassCtor body)

member this.PrependInstructionsToSpecificMethodDef(cond, instrs, tag, imports) =
match ResizeArray.tryFindIndex cond gmethods with
| Some idx -> gmethods[idx] <- prependInstrsToMethod instrs gmethods[idx]
| None ->
Expand All @@ -1917,6 +1926,8 @@ type TypeDefBuilder(tdef: ILTypeDef, tdefDiscards) =

gmethods.Add(mkILClassCtor body)

this

and TypeDefsBuilder() =

let tdefs =
Expand Down Expand Up @@ -2264,6 +2275,22 @@ and AssemblyBuilder(cenv: cenv, anonTypeTable: AnonTypeGenerationTable) as mgbuf
/// static init fields on script modules.
let scriptInitFspecs = ConcurrentStack<ILFieldSpec * range>()

let initialInstrs seqpt feefee =
[
yield!
(if isEnvVarSet "NO_ADD_FEEFEE_TO_CCTORS" then []
elif isEnvVarSet "ADD_SEQPT_TO_CCTORS" then seqpt
else feefee) // mark start of hidden code
]

let finalInstrs fspec =
[
yield mkLdcInt32 0
yield mkNormalStsfld fspec
yield mkNormalLdsfld fspec
yield AI_pop
]

member _.AddScriptInitFieldSpec(fieldSpec, range) =
scriptInitFspecs.Push((fieldSpec, range))

Expand All @@ -2276,15 +2303,7 @@ and AssemblyBuilder(cenv: cenv, anonTypeTable: AnonTypeGenerationTable) as mgbuf
let InitializeCompiledScript (fspec, m) =
let ilDebugRange = GenPossibleILDebugRange cenv m

mgbuf.AddExplicitInitToSpecificMethodDef(
(fun (md: ILMethodDef) -> md.IsEntryPoint),
tref,
fspec,
ilDebugRange,
imports,
[],
[]
)
mgbuf.AddExplicitInitToEntryPoint(tref, fspec, ilDebugRange, imports, [], [])

scriptInitFspecs |> Seq.iter InitializeCompiledScript
| None -> ()
Expand Down Expand Up @@ -2325,24 +2344,23 @@ and AssemblyBuilder(cenv: cenv, anonTypeTable: AnonTypeGenerationTable) as mgbuf
if ilMethodDef.IsEntryPoint then
explicitEntryPointInfo <- Some tref

member _.AddExplicitInitToSpecificMethodDef(cond, tref, fspec, sourceOpt, imports, feefee, seqpt) =
// Authoring a .cctor with effects forces the cctor for the 'initialization' module by doing a dummy store & load of a field
// Doing both a store and load keeps FxCop happier because it thinks the field is useful
let instrs =
[
yield!
(if isEnvVarSet "NO_ADD_FEEFEE_TO_CCTORS" then []
elif isEnvVarSet "ADD_SEQPT_TO_CCTORS" then seqpt
else feefee) // mark start of hidden code
yield mkLdcInt32 0
yield mkNormalStsfld fspec
yield mkNormalLdsfld fspec
yield AI_pop
]
member _.AddExplicitInitToEntryPoint(tref, fspec, sourceOpt, imports, feefee, seqpt) =

let cond = (fun (md: ILMethodDef) -> md.IsEntryPoint)

gtdefs
.FindNestedTypeDefBuilder(tref)
.PrependInstructionsToSpecificMethodDef(cond, instrs, sourceOpt, imports)
.PrependInstructionsToSpecificMethodDef(cond, (initialInstrs seqpt feefee) @ (finalInstrs fspec), sourceOpt, imports)
|> ignore

member _.AddExplicitInitToCctor(tref, fspec, sourceOpt, imports, feefee, seqpt) =

let cond = (fun (md: ILMethodDef) -> md.Name = ".cctor")

gtdefs
.FindNestedTypeDefBuilder(tref)
.PrependInstructionsToSpecificMethodDef(cond, initialInstrs seqpt feefee, sourceOpt, imports)
.AppendInstructionsToSpecificMethodDef(cond, finalInstrs fspec, sourceOpt, imports)

member _.AddEventDef(tref, edef) =
gtdefs.FindNestedTypeDefBuilder(tref).AddEventDef(edef)
Expand Down Expand Up @@ -10194,15 +10212,7 @@ and GenImplFile cenv (mgbuf: AssemblyBuilder) mainInfoOpt eenv (implFile: Checke
// This adds the explicit init of the .cctor to the explicit entry point main method
let ilDebugRange = GenPossibleILDebugRange cenv m

mgbuf.AddExplicitInitToSpecificMethodDef(
(fun md -> md.IsEntryPoint),
tref,
fspec,
ilDebugRange,
eenv.imports,
feefee,
seqpt
))
mgbuf.AddExplicitInitToEntryPoint(tref, fspec, ilDebugRange, eenv.imports, feefee, seqpt))

let cctorMethDef =
mkILClassCtor (MethodBody.IL(InterruptibleLazy.FromValue topCode))
Expand Down Expand Up @@ -10289,7 +10299,7 @@ and GenForceWholeFileInitializationAsPartOfCCtor cenv (mgbuf: AssemblyBuilder) (
// Doing both a store and load keeps FxCop happier because it thinks the field is useful
lazyInitInfo.Add(fun fspec feefee seqpt ->
let ilDebugRange = GenPossibleILDebugRange cenv m
mgbuf.AddExplicitInitToSpecificMethodDef((fun md -> md.Name = ".cctor"), tref, fspec, ilDebugRange, imports, feefee, seqpt))
mgbuf.AddExplicitInitToCctor(tref, fspec, ilDebugRange, imports, feefee, seqpt))

/// Generate an Equals method.
and GenEqualsOverrideCallingIComparable cenv (tcref: TyconRef, ilThisTy, _ilThatTy) =
Expand Down
45 changes: 32 additions & 13 deletions src/Compiler/Service/ServiceParseTreeWalk.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1163,8 +1163,8 @@ module SyntaxNode =

[<RequireQualifiedAccess>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module ParsedInput =
let fold folder state (parsedInput: ParsedInput) =
module internal SyntaxNodes =
let fold folder state (ast: SyntaxNode list) =
let mutable state = state

let visitor =
Expand Down Expand Up @@ -1270,7 +1270,6 @@ module ParsedInput =

loop diveResults

let ast = parsedInput.Contents
let m = (range0, ast) ||> List.fold (fun acc node -> unionRanges acc node.Range)
ignore<unit option> (SyntaxTraversal.traverseUntil pickAll m.End visitor ast)
state
Expand Down Expand Up @@ -1454,7 +1453,7 @@ module ParsedInput =
ignore<unit option> (SyntaxTraversal.traverseUntil pick pos visitor ast)
state

let foldWhile folder state (parsedInput: ParsedInput) =
let foldWhile folder state (ast: SyntaxNode list) =
let pickAll _ _ _ diveResults =
let rec loop diveResults =
match diveResults with
Expand All @@ -1465,11 +1464,10 @@ module ParsedInput =

loop diveResults

let ast = parsedInput.Contents
let m = (range0, ast) ||> List.fold (fun acc node -> unionRanges acc node.Range)
foldWhileImpl pickAll m.End folder state ast

let tryPick chooser position (parsedInput: ParsedInput) =
let tryPick chooser position (ast: SyntaxNode list) =
let visitor =
{ new SyntaxVisitorBase<'T>() with
member _.VisitExpr(path, _, defaultTraverse, expr) =
Expand Down Expand Up @@ -1545,25 +1543,46 @@ module ParsedInput =
| _ -> None
}

SyntaxTraversal.traverseUntil SyntaxTraversal.pick position visitor parsedInput.Contents
SyntaxTraversal.traverseUntil SyntaxTraversal.pick position visitor ast

let tryPickLast chooser position (parsedInput: ParsedInput) =
(None, parsedInput.Contents)
let tryPickLast chooser position (ast: SyntaxNode list) =
(None, ast)
||> foldWhileImpl SyntaxTraversal.pick position (fun prev path node ->
match chooser path node with
| Some _ as next -> Some next
| None -> Some prev)

let tryNode position (parsedInput: ParsedInput) =
let tryNode position (ast: SyntaxNode list) =
let Matching = Some

(None, parsedInput.Contents)
(None, ast)
||> foldWhileImpl SyntaxTraversal.pick position (fun _prev path node ->
if rangeContainsPos node.Range position then
Some(Matching(node, path))
else
None)

let exists predicate position parsedInput =
tryPick (fun path node -> if predicate path node then Some() else None) position parsedInput
let exists predicate position ast =
tryPick (fun path node -> if predicate path node then Some() else None) position ast
|> Option.isSome

[<RequireQualifiedAccess>]
[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>]
module ParsedInput =
let fold folder state (parsedInput: ParsedInput) =
SyntaxNodes.fold folder state parsedInput.Contents

let foldWhile folder state (parsedInput: ParsedInput) =
SyntaxNodes.foldWhile folder state parsedInput.Contents

let tryPick chooser position (parsedInput: ParsedInput) =
SyntaxNodes.tryPick chooser position parsedInput.Contents

let tryPickLast chooser position (parsedInput: ParsedInput) =
SyntaxNodes.tryPickLast chooser position parsedInput.Contents

let tryNode position (parsedInput: ParsedInput) =
SyntaxNodes.tryNode position parsedInput.Contents

let exists predicate position (parsedInput: ParsedInput) =
SyntaxNodes.exists predicate position parsedInput.Contents
Loading
Loading