Skip to content

Commit 4de226a

Browse files
authored
Merge branch 'main' into ber,a/fixLetBangTree
2 parents 4df2bf6 + 1ff7cb1 commit 4de226a

File tree

10 files changed

+114
-26
lines changed

10 files changed

+114
-26
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,10 @@
22

33
* Scripts: Fix resolving the dotnet host path when an SDK directory is specified. ([PR #18960](https://github.com/dotnet/fsharp/pull/18960))
44
* Fix excessive StackGuard thread jumping ([PR #18971](https://github.com/dotnet/fsharp/pull/18971))
5+
* Checking: Fix checking nested fields for records and anonymous ([PR #18964](https://github.com/dotnet/fsharp/pull/18964))
56
* Fix name is bound multiple times is not reported in 'as' pattern ([PR #18984](https://github.com/dotnet/fsharp/pull/18984))
67
* Syntax Tree: fix return type info for let! / and! / use! ([PR #19004](https://github.com/dotnet/fsharp/pull/19004))
8+
* Type relations cache: handle potentially "infinite" types ([PR #19010](https://github.com/dotnet/fsharp/pull/19010))
79

810
### Added
911

eng/Version.Details.props

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ This file should be imported by eng/Versions.props
66
<Project>
77
<PropertyGroup>
88
<!-- dotnet/msbuild dependencies -->
9-
<MicrosoftBuildPackageVersion>18.1.0-preview-25514-02</MicrosoftBuildPackageVersion>
10-
<MicrosoftBuildFrameworkPackageVersion>18.1.0-preview-25514-02</MicrosoftBuildFrameworkPackageVersion>
11-
<MicrosoftBuildTasksCorePackageVersion>18.1.0-preview-25514-02</MicrosoftBuildTasksCorePackageVersion>
12-
<MicrosoftBuildUtilitiesCorePackageVersion>18.1.0-preview-25514-02</MicrosoftBuildUtilitiesCorePackageVersion>
9+
<MicrosoftBuildPackageVersion>18.1.0-preview-25515-01</MicrosoftBuildPackageVersion>
10+
<MicrosoftBuildFrameworkPackageVersion>18.1.0-preview-25515-01</MicrosoftBuildFrameworkPackageVersion>
11+
<MicrosoftBuildTasksCorePackageVersion>18.1.0-preview-25515-01</MicrosoftBuildTasksCorePackageVersion>
12+
<MicrosoftBuildUtilitiesCorePackageVersion>18.1.0-preview-25515-01</MicrosoftBuildUtilitiesCorePackageVersion>
1313
<!-- dotnet/runtime dependencies -->
1414
<SystemCollectionsImmutablePackageVersion>9.0.0</SystemCollectionsImmutablePackageVersion>
1515
<SystemComponentModelCompositionPackageVersion>9.0.0</SystemComponentModelCompositionPackageVersion>

eng/Version.Details.xml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
<Dependencies>
33
<Source Uri="https://github.com/dotnet/dotnet" Mapping="fsharp" Sha="01abb3ec5c4cbffec5b33e02156bd3d2a8913b04" BarId="286825" />
44
<ProductDependencies>
5-
<Dependency Name="Microsoft.Build" Version="18.1.0-preview-25514-02">
5+
<Dependency Name="Microsoft.Build" Version="18.1.0-preview-25515-01">
66
<Uri>https://github.com/dotnet/msbuild</Uri>
7-
<Sha>ce41c053ea92f0f9cf5f68d44015490ec30edfa6</Sha>
7+
<Sha>5e273ccd45ba73d9db9b34fceaf9a110412e64e8</Sha>
88
</Dependency>
9-
<Dependency Name="Microsoft.Build.Framework" Version="18.1.0-preview-25514-02">
9+
<Dependency Name="Microsoft.Build.Framework" Version="18.1.0-preview-25515-01">
1010
<Uri>https://github.com/dotnet/msbuild</Uri>
11-
<Sha>ce41c053ea92f0f9cf5f68d44015490ec30edfa6</Sha>
11+
<Sha>5e273ccd45ba73d9db9b34fceaf9a110412e64e8</Sha>
1212
</Dependency>
13-
<Dependency Name="Microsoft.Build.Tasks.Core" Version="18.1.0-preview-25514-02">
13+
<Dependency Name="Microsoft.Build.Tasks.Core" Version="18.1.0-preview-25515-01">
1414
<Uri>https://github.com/dotnet/msbuild</Uri>
15-
<Sha>ce41c053ea92f0f9cf5f68d44015490ec30edfa6</Sha>
15+
<Sha>5e273ccd45ba73d9db9b34fceaf9a110412e64e8</Sha>
1616
</Dependency>
17-
<Dependency Name="Microsoft.Build.Utilities.Core" Version="18.1.0-preview-25514-02">
17+
<Dependency Name="Microsoft.Build.Utilities.Core" Version="18.1.0-preview-25515-01">
1818
<Uri>https://github.com/dotnet/msbuild</Uri>
19-
<Sha>ce41c053ea92f0f9cf5f68d44015490ec30edfa6</Sha>
19+
<Sha>5e273ccd45ba73d9db9b34fceaf9a110412e64e8</Sha>
2020
</Dependency>
2121
<Dependency Name="System.Reflection.Metadata" Version="9.0.0">
2222
<Uri>https://github.com/dotnet/runtime</Uri>

eng/Versions.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
<FSharpCorePreviewPackageVersionValue>$(FSCorePackageVersionValue)-$(PreReleaseVersionLabel).*</FSharpCorePreviewPackageVersionValue>
4747
<!-- -->
4848
<!-- FSharp tools for Visual Studio version number -->
49-
<FSToolsMajorVersion>14</FSToolsMajorVersion>
49+
<FSToolsMajorVersion>15</FSToolsMajorVersion>
5050
<FSToolsMinorVersion>0</FSToolsMinorVersion>
5151
<FSToolsBuildVersion>$(FSBuildVersion)</FSToolsBuildVersion>
5252
<FSToolsRevisionVersion>$(FSRevisionVersion)</FSToolsRevisionVersion>

src/Compiler/Checking/CheckRecordSyntaxHelpers.fs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,26 @@ let TransformAstForNestedUpdates (cenv: TcFileState) (env: TcEnv) overallTy (lid
156156
(accessIds, outerFieldId),
157157
Some(synExprRecd (recdExprCopyInfo (fields |> List.map fst) withExpr) outerFieldId rest exprBeingAssigned)
158158

159+
/// This name is used when a complex expression is bound for use as a binding in a copy-and-update expression.
160+
/// For example, in `{ f () with ... }`, `f ()` is replaced by `let bind@ = f ()`
161+
let BindIdText = "bind@"
162+
163+
/// Finding the 'bind@' identifier is the only way to detect that an expression has already been bound.
164+
let inline (|IsSimpleOrBoundExpr|_|) (withExprOpt: (SynExpr * BlockSeparator) option) =
165+
match withExprOpt with
166+
| None -> true
167+
| Some(expr, _) ->
168+
match expr with
169+
| SynExpr.LongIdent(_, lIds, _, _) -> lIds.LongIdent |> List.exists (fun id -> id.idText = BindIdText)
170+
| SynExpr.Ident _ -> true
171+
| _ -> false
172+
159173
/// When the original expression in copy-and-update is more complex than `{ x with ... }`, like `{ f () with ... }`,
160174
/// we bind it first, so that it's not evaluated multiple times during a nested update
161175
let BindOriginalRecdExpr (withExpr: SynExpr * BlockSeparator) mkRecdExpr =
162176
let originalExpr, blockSep = withExpr
163177
let mOrigExprSynth = originalExpr.Range.MakeSynthetic()
164-
let id = mkSynId mOrigExprSynth "bind@"
178+
let id = mkSynId mOrigExprSynth BindIdText
165179
let withExpr = SynExpr.Ident id, blockSep
166180

167181
let binding =

src/Compiler/Checking/CheckRecordSyntaxHelpers.fsi

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,9 @@ val TransformAstForNestedUpdates<'a> :
1919
withExpr: SynExpr * (range * 'a) ->
2020
(Ident list * Ident) * SynExpr option
2121

22+
val BindIdText: string
23+
24+
val inline (|IsSimpleOrBoundExpr|_|): withExprOpt: (SynExpr * BlockSeparator) option -> bool
25+
2226
val BindOriginalRecdExpr:
2327
withExpr: SynExpr * BlockSeparator -> mkRecdExpr: ((SynExpr * BlockSeparator) option -> SynExpr) -> SynExpr

src/Compiler/Checking/Expressions/CheckExpressions.fs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5895,9 +5895,8 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE
58955895
TcExprTuple cenv overallTy env tpenv (isExplicitStruct, args, m)
58965896

58975897
| SynExpr.AnonRecd (isStruct, withExprOpt, unsortedFieldExprs, mWholeExpr, trivia) ->
5898-
match withExprOpt with
5899-
| None
5900-
| Some(SynExpr.Ident _, _) ->
5898+
match withExprOpt with
5899+
| None | IsSimpleOrBoundExpr ->
59015900
TcNonControlFlowExpr env <| fun env ->
59025901
TcPossiblyPropagatingExprLeafThenConvert (fun ty -> isAnonRecdTy g ty || isTyparTy g ty) cenv overallTy env mWholeExpr (fun overallTy ->
59035902
TcAnonRecdExpr cenv overallTy env tpenv (isStruct, withExprOpt, unsortedFieldExprs, mWholeExpr)
@@ -5929,10 +5928,9 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE
59295928
let binds = unionBindingAndMembers binds members
59305929
TcExprObjectExpr cenv overallTy env tpenv (synObjTy, argopt, binds, extraImpls, mNewExpr, m)
59315930

5932-
| SynExpr.Record (inherits, withExprOpt, synRecdFields, mWholeExpr) ->
5931+
| SynExpr.Record (inherits, withExprOpt, synRecdFields, mWholeExpr) ->
59335932
match withExprOpt with
5934-
| None
5935-
| Some(SynExpr.Ident _, _) ->
5933+
| None | IsSimpleOrBoundExpr ->
59365934
TcNonControlFlowExpr env <| fun env ->
59375935
TcExprRecord cenv overallTy env tpenv (inherits, withExprOpt, synRecdFields, mWholeExpr)
59385936
| Some withExpr ->

src/Compiler/Checking/TypeRelations.fs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ type CanCoerce =
2828
[<Struct; NoComparison>]
2929
type TTypeCacheKey =
3030
| TTypeCacheKey of TypeStructure * TypeStructure * CanCoerce
31-
static member FromStrippedTypes(ty1, ty2, canCoerce) =
32-
TTypeCacheKey(getTypeStructure ty1, getTypeStructure ty2, canCoerce)
31+
static member TryGetFromStrippedTypes(ty1, ty2, canCoerce) =
32+
let t1, t2 = getTypeStructure ty1, getTypeStructure ty2
33+
if t1.IsPossiblyInfinite || t2.IsPossiblyInfinite then
34+
ValueNone
35+
else
36+
ValueSome (TTypeCacheKey(t1, t2, canCoerce))
3337

3438
let getTypeSubsumptionCache =
3539
let factory (g: TcGlobals) =
@@ -157,8 +161,10 @@ let rec TypeFeasiblySubsumesType ndeep (g: TcGlobals) (amap: ImportMap) m (ty1:
157161
List.exists (TypeFeasiblySubsumesType (ndeep + 1) g amap m ty1 NoCoerce) interfaces
158162

159163
if g.langVersion.SupportsFeature LanguageFeature.UseTypeSubsumptionCache then
160-
let key = TTypeCacheKey.FromStrippedTypes(ty1, ty2, canCoerce)
161-
(getTypeSubsumptionCache g).GetOrAdd(key, fun _ -> checkSubsumes ty1 ty2)
164+
match TTypeCacheKey.TryGetFromStrippedTypes(ty1, ty2, canCoerce) with
165+
| ValueSome key ->
166+
(getTypeSubsumptionCache g).GetOrAdd(key, fun _ -> checkSubsumes ty1 ty2)
167+
| _ -> checkSubsumes ty1 ty2
162168
else
163169
checkSubsumes ty1 ty2
164170

src/Compiler/Utilities/TypeHashing.fs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,9 @@ module StructuralUtilities =
401401
| MeasureRational of int * int
402402
| NeverEqual of never: NeverEqual
403403

404-
type TypeStructure = TypeStructure of ImmutableArray<TypeToken>
404+
type TypeStructure =
405+
| TypeStructure of TypeToken[]
406+
| PossiblyInfinite of never: NeverEqual
405407

406408
let inline toNullnessToken (n: Nullness) =
407409
match n.TryEvaluate() with
@@ -464,6 +466,15 @@ module StructuralUtilities =
464466
| TType_measure m -> yield! accumulateMeasure m
465467
}
466468

469+
// If the sequence got too long, just drop it, we could be dealing with an infinite type.
470+
let private toTypeStructure tokens =
471+
let tokens = tokens |> Seq.truncate 256 |> Array.ofSeq
472+
473+
if tokens.Length = 256 then
474+
PossiblyInfinite NeverEqual.Singleton
475+
else
476+
TypeStructure tokens
477+
467478
/// Get the full structure of a type as a sequence of tokens, suitable for equality
468479
let getTypeStructure =
469-
Extras.WeakMap.getOrCreate (fun ty -> accumulateTType ty |> ImmutableArray.ofSeq |> TypeStructure)
480+
Extras.WeakMap.getOrCreate (fun ty -> accumulateTType ty |> toTypeStructure)

tests/FSharp.Compiler.ComponentTests/Language/CopyAndUpdateTests.fs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -480,3 +480,56 @@ if actual <> expected then
480480
|> withLangVersion80
481481
|> compileExeAndRun
482482
|> verifyOutput "once"
483+
484+
[<Fact>]
485+
let ``N-Nested copy-and-update works when the starting expression is not a simple identifier``() =
486+
FSharp """
487+
module CopyAndUpdateTests
488+
type SubSubTest = {
489+
Z: int
490+
}
491+
492+
type SubTest = {
493+
Y: SubSubTest
494+
}
495+
496+
type Test = {
497+
X: SubTest
498+
}
499+
500+
let getTest () =
501+
{ X = { Y = { Z = 0 } } }
502+
503+
[<EntryPoint>]
504+
let main argv =
505+
let a = {
506+
getTest () with
507+
X.Y.Z = 1
508+
}
509+
printfn "%i" a.X.Y.Z |> ignore
510+
0
511+
"""
512+
|> typecheck
513+
|> shouldSucceed
514+
|> verifyOutput "1"
515+
516+
[<Fact>]
517+
let ``N-Nested, anonymous copy-and-update works when the starting expression is not a simple identifier``() =
518+
FSharp """
519+
module CopyAndUpdateTests
520+
521+
let getTest () =
522+
{| X = {| Y = {| Z = 0 |} |} |}
523+
524+
[<EntryPoint>]
525+
let main argv =
526+
let a = {|
527+
getTest () with
528+
X.Y.Z = 1
529+
|}
530+
printfn "%i" a.X.Y.Z |> ignore
531+
0
532+
"""
533+
|> typecheck
534+
|> shouldSucceed
535+
|> verifyOutput "1"

0 commit comments

Comments
 (0)