Skip to content

Commit 9f360ed

Browse files
KevinRansomT-Gropsfinaki
authored
Fix #17797 -- Realsig+ generates nested closures with incorrect Generic arguments (#17877)
* tests * code * baseline * fantomas * release notes * ilverify baselines * Update tests/FSharp.Compiler.ComponentTests/Conformance/LexicalAnalysis/SymbolicOperators.fs Yeah the comments are pointless. Co-authored-by: Tomas Grosup <[email protected]> * Feedback pt 1 * temp * tests * release notes * debug * Update DEVGUIDE.md Co-authored-by: Petr <[email protected]> --------- Co-authored-by: Tomas Grosup <[email protected]> Co-authored-by: Petr <[email protected]>
1 parent c350a41 commit 9f360ed

File tree

168 files changed

+26831
-3758
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

168 files changed

+26831
-3758
lines changed

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,9 @@ tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstanda
129129
/tests/AheadOfTime/Trimming/output.txt
130130
*.svclog
131131
micro.exe
132-
positive.exe
132+
positive.exe
133+
/tests/FSharp.Compiler.ComponentTests/FSharpChecker/StandardError.txt
134+
/tests/FSharp.Compiler.ComponentTests/FSharpChecker/StandardOutput.txt
135+
136+
# ilverify baseline result files
137+
*.bsl.actual

DEVGUIDE.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,33 @@ Linux/macOS:
204204
export TEST_UPDATE_BSL=1
205205
```
206206

207+
## Retain Test run built artifacts
208+
209+
When investigating tests issues it is sometimes useful to examine the artifacts built when running tests. Those built using the newer test framework are usually,
210+
built in the %TEMP%\FSharp.Test.Utilities subdirectory.
211+
212+
To tell the test framework to not cleanup these files use the: FSHARP_RETAIN_TESTBUILDS environment variable
213+
214+
Windows:
215+
216+
CMD:
217+
218+
```shell
219+
set FSHARP_RETAIN_TESTBUILDS=1
220+
```
221+
222+
PowerShell:
223+
224+
```shell
225+
$env:FSHARP_RETAIN_TESTBUILDS=1
226+
```
227+
228+
Linux/macOS:
229+
230+
```shell
231+
export FSHARP_RETAIN_TESTBUILDS=1
232+
```
233+
207234
Next, run a build script build (debug or release, desktop or coreclr, depending which baselines you need to update), and test as described [above](#Testing-from-the-command-line). For example:
208235

209236
`./Build.cmd -c Release -testCoreClr` to update Release CoreCLR baselines.

docs/release-notes/.FSharp.Compiler.Service/9.0.200.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
### Fixed
22

3+
* Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877))
34
* Fix missing TailCall warning in Sequential in use scope ([PR #17927](https://github.com/dotnet/fsharp/pull/17927))
45
* Fix false negatives for passing null to "obj" arguments. Only "obj | null" can now subsume any type ([PR #17757](https://github.com/dotnet/fsharp/pull/17757))
56
* Fix internal error when calling 'AddSingleton' and other overloads only differing in generic arity ([PR #17804](https://github.com/dotnet/fsharp/pull/17804))
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
### Fixed
2+
3+
* Fix Realsig+ generates nested closures with incorrect Generic ([Issue #17797](https://github.com/dotnet/fsharp/issues/17797), [PR #17877](https://github.com/dotnet/fsharp/pull/17877))
4+
5+
### Added
6+
7+
8+
### Changed
9+
10+
11+
### Breaking Changes
12+

src/Compiler/CodeGen/IlxGen.fs

Lines changed: 39 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -521,7 +521,8 @@ let ComputeTypeAccess (tref: ILTypeRef) hidden (accessibility: Accessibility) re
521521

522522
/// Indicates how type parameters are mapped to IL type variables
523523
[<NoEquality; NoComparison>]
524-
type TypeReprEnv(reprs: Map<Stamp, uint16>, count: int, templateReplacement: (TyconRef * ILTypeRef * Typars * TyparInstantiation) option) =
524+
type TypeReprEnv
525+
(reprs: Map<Stamp, (uint16 * Typar)>, count: int, templateReplacement: (TyconRef * ILTypeRef * Typars * TyparInstantiation) option) =
525526

526527
static let empty = TypeReprEnv(count = 0, reprs = Map.empty, templateReplacement = None)
527528

@@ -536,7 +537,7 @@ type TypeReprEnv(reprs: Map<Stamp, uint16>, count: int, templateReplacement: (Ty
536537
/// Lookup a type parameter
537538
member _.Item(tp: Typar, m: range) =
538539
try
539-
reprs[tp.Stamp]
540+
reprs[tp.Stamp] |> fst
540541
with :? KeyNotFoundException ->
541542
errorR (InternalError("Undefined or unsolved type variable: " + showL (typarL tp), m))
542543
// Random value for post-hoc diagnostic analysis on generated tree *
@@ -546,7 +547,7 @@ type TypeReprEnv(reprs: Map<Stamp, uint16>, count: int, templateReplacement: (Ty
546547
/// then it is ignored, since it doesn't correspond to a .NET type parameter.
547548
member tyenv.AddOne(tp: Typar) =
548549
if IsNonErasedTypar tp then
549-
TypeReprEnv(reprs.Add(tp.Stamp, uint16 count), count + 1, templateReplacement)
550+
TypeReprEnv(reprs.Add(tp.Stamp, (uint16 count, tp)), count + 1, templateReplacement)
550551
else
551552
tyenv
552553

@@ -573,6 +574,14 @@ type TypeReprEnv(reprs: Map<Stamp, uint16>, count: int, templateReplacement: (Ty
573574
/// Get the environment for generating a reference to items within a type definition
574575
member eenv.ForTyconRef(tcref: TyconRef) = eenv.ForTycon tcref.Deref
575576

577+
/// Get a list of the Typars in this environment
578+
member eenv.AsUserProvidedTypars() =
579+
reprs
580+
|> Map.toList
581+
|> List.map (fun (_, (_, tp)) -> tp)
582+
|> List.filter (fun tp -> not tp.IsCompilerGenerated)
583+
|> Zset.ofList typarOrder
584+
576585
//--------------------------------------------------------------------------
577586
// Generate type references
578587
//--------------------------------------------------------------------------
@@ -6904,14 +6913,6 @@ and GenFreevar cenv m eenvouter tyenvinner (fv: Val) =
69046913
and GetIlxClosureFreeVars cenv m (thisVars: ValRef list) boxity eenv takenNames expr =
69056914
let g = cenv.g
69066915

6907-
// Choose a base name for the closure
6908-
let basename =
6909-
let boundv = eenv.letBoundVars |> List.tryFind (fun v -> not v.IsCompilerGenerated)
6910-
6911-
match boundv with
6912-
| Some v -> v.CompiledName cenv.g.CompilerGlobalState
6913-
| None -> "clo"
6914-
69156916
// Get a unique stamp for the closure. This must be stable for things that can be part of a let rec.
69166917
let uniq =
69176918
match expr with
@@ -6921,18 +6922,34 @@ and GetIlxClosureFreeVars cenv m (thisVars: ValRef list) boxity eenv takenNames
69216922
| _ -> newUnique ()
69226923

69236924
// Choose a name for the closure
6924-
let ilCloTypeRef =
6925+
let ilCloTypeRef, initialFreeTyvars =
6926+
let boundvar =
6927+
eenv.letBoundVars |> List.tryFind (fun v -> not v.IsCompilerGenerated)
6928+
6929+
let basename =
6930+
match boundvar with
6931+
| Some v -> v.CompiledName cenv.g.CompilerGlobalState
6932+
| None -> "clo"
6933+
69256934
// FSharp 1.0 bug 3404: System.Reflection doesn't like '.' and '`' in type names
69266935
let basenameSafeForUseAsTypename = CleanUpGeneratedTypeName basename
69276936

6928-
let suffixmark = expr.Range
6929-
69306937
let cloName =
69316938
// Ensure that we have an g.CompilerGlobalState
69326939
assert (g.CompilerGlobalState |> Option.isSome)
6933-
g.CompilerGlobalState.Value.StableNameGenerator.GetUniqueCompilerGeneratedName(basenameSafeForUseAsTypename, suffixmark, uniq)
6940+
g.CompilerGlobalState.Value.StableNameGenerator.GetUniqueCompilerGeneratedName(basenameSafeForUseAsTypename, expr.Range, uniq)
6941+
6942+
let ilCloTypeRef = NestedTypeRefForCompLoc eenv.cloc cloName
69346943

6935-
NestedTypeRefForCompLoc eenv.cloc cloName
6944+
let initialFreeTyvars =
6945+
match g.realsig with
6946+
| true ->
6947+
{ emptyFreeTyvars with
6948+
FreeTypars = eenv.tyenv.AsUserProvidedTypars()
6949+
}
6950+
| false -> emptyFreeTyvars
6951+
6952+
ilCloTypeRef, initialFreeTyvars
69366953

69376954
// Collect the free variables of the closure
69386955
let cloFreeVarResults =
@@ -6943,7 +6960,12 @@ and GetIlxClosureFreeVars cenv m (thisVars: ValRef list) boxity eenv takenNames
69436960
| None -> opts
69446961
| Some(tcref, _, typars, _) -> opts.WithTemplateReplacement(tyconRefEq g tcref, typars)
69456962

6946-
freeInExpr opts expr
6963+
accFreeInExpr
6964+
opts
6965+
expr
6966+
{ emptyFreeVars with
6967+
FreeTyvars = initialFreeTyvars
6968+
}
69476969

69486970
// Partition the free variables when some can be accessed from places besides the immediate environment
69496971
// Also filter out the current value being bound, if any, as it is available from the "this"

src/Compiler/TypedTree/CompilerGlobalState.fs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,6 @@ let newUnique() = System.Threading.Interlocked.Increment &uniqueCount
7373
/// Unique name generator for stamps attached to to val_specs, tycon_specs etc.
7474
//++GLOBAL MUTABLE STATE (concurrency-safe)
7575
let mutable private stampCount = 0L
76-
let newStamp() = System.Threading.Interlocked.Increment &stampCount
76+
let newStamp() =
77+
let stamp = System.Threading.Interlocked.Increment &stampCount
78+
stamp

src/Compiler/TypedTree/TypedTreeOps.fsi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,6 +1186,9 @@ val accFreeInDecisionTree: FreeVarOptions -> DecisionTree -> FreeVars -> FreeVar
11861186
/// Get the free variables in a module definition.
11871187
val freeInModuleOrNamespace: FreeVarOptions -> ModuleOrNamespaceContents -> FreeVars
11881188

1189+
/// Get the free variables in an expression with accumulator
1190+
val accFreeInExpr: FreeVarOptions -> Expr -> FreeVars -> FreeVars
1191+
11891192
/// Get the free variables in an expression.
11901193
val freeInExpr: FreeVarOptions -> Expr -> FreeVars
11911194

tests/FSharp.Compiler.ComponentTests/Conformance/LexicalAnalysis/SymbolicOperators.fs

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,38 @@ module SymbolicOperators =
3131

3232
// This test was automatically generated (moved from FSharpQA suite - Conformance/LexicalAnalysis/SymbolicOperators)
3333
//<Expects status="error" id="FS0670">This code is not sufficiently generic\. The type variable \^T when \^T : \(static member \( \+ \) : \^T \* \^T -> \^a\) could not be generalized because it would escape its scope</Expects>
34-
[<Theory; Directory(__SOURCE_DIRECTORY__ + "/../../resources/tests/Conformance/LexicalAnalysis/SymbolicOperators", Includes=[|"E_LessThanDotOpenParen001.fs"|])>]
35-
let ``SymbolicOperators - E_LessThanDotOpenParen001_fs - --flaterrors`` compilation =
36-
compilation
37-
|> asFsx
34+
[<InlineData(true)>] // RealSig
35+
[<InlineData(false)>] // Regular
36+
[<Theory>]
37+
let ``SymbolicOperators_E_LessThanDotOpenParen001_fs`` (realsig) =
38+
Fsx """
39+
40+
type public TestType<'T,'S>() =
41+
42+
member public s.Value with get() = Unchecked.defaultof<'T>
43+
static member public (+++) (a : TestType<'T,'S>, b : TestType<'T,'S>) = a.Value
44+
static member public (+++) (a : TestType<'T,'S>, b : 'T) = b
45+
static member public (+++) (a : 'T, b : TestType<'T,'S>) = a
46+
static member public (+++) (a : TestType<'T,'S>, b : 'T -> 'S) = a.Value
47+
static member public (+++) (a : 'S -> 'T, b : TestType<'T,'S>) = (a 17) + b.Value
48+
49+
let inline (+++) (a : ^a) (b : ^b) = ((^a or ^b): (static member (+++): ^a * ^b -> ^c) (a,b) )
50+
51+
let tt0 = TestType<int, string>()
52+
let tt1 = TestType<int, string>()
53+
54+
let f (x : string) = 18
55+
56+
let a0 = tt0 +++ tt1
57+
let a1 = tt0 +++ 11
58+
let a2 = 12 +++ tt1
59+
let a3 = tt0 +++ (fun x -> "18")
60+
let a4 = f +++ tt0
61+
62+
let a5 = TestType<int, string>.(+++)(f, tt0)
63+
let a6 = TestType<int, string>.(+++)((fun (x : string) -> 18), tt0)"""
3864
|> withOptions ["--flaterrors"]
65+
|> withRealInternalSignature realsig
3966
|> compile
4067
|> shouldFail
4168
|> withErrorCode 0670

0 commit comments

Comments
 (0)