Skip to content

Commit 0d3549f

Browse files
authored
Merge pull request #15858 from dotnet/merges/main-to-release/dev17.8
2 parents 2c7c1eb + 58a0da2 commit 0d3549f

File tree

59 files changed

+1261
-634
lines changed

Some content is hidden

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

59 files changed

+1261
-634
lines changed

src/Compiler/Checking/CheckExpressions.fs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1796,6 +1796,12 @@ let FreshenAbstractSlot g amap m synTyparDecls absMethInfo =
17961796
let retTyFromAbsSlot = retTy |> GetFSharpViewOfReturnType g |> instType typarInstFromAbsSlot
17971797
typarsFromAbsSlotAreRigid, typarsFromAbsSlot, argTysFromAbsSlot, retTyFromAbsSlot
17981798

1799+
let CheckRecdExprDuplicateFields (elems: Ident list) =
1800+
elems |> List.iteri (fun i (uc1: Ident) ->
1801+
elems |> List.iteri (fun j (uc2: Ident) ->
1802+
if j > i && uc1.idText = uc2.idText then
1803+
errorR (Error(FSComp.SR.tcMultipleFieldsInRecord(uc1.idText), uc1.idRange))))
1804+
17991805
//-------------------------------------------------------------------------
18001806
// Helpers to typecheck expressions and patterns
18011807
//-------------------------------------------------------------------------
@@ -1807,9 +1813,14 @@ let BuildFieldMap (cenv: cenv) env isPartial ty (flds: ((Ident list * Ident) * '
18071813

18081814
if isNil flds then invalidArg "flds" "BuildFieldMap"
18091815

1810-
let fldCount = flds.Length
1816+
let allFields = flds |> List.map (fun ((_, ident), _) -> ident)
1817+
if allFields.Length > 1 then
1818+
// In the case of nested record fields on the same level in record copy-and-update.
1819+
// We need to reverse the list to get the correct order of fields.
1820+
let idents = if isPartial then allFields |> List.rev else allFields
1821+
CheckRecdExprDuplicateFields idents
1822+
18111823
let fldResolutions =
1812-
let allFields = flds |> List.map (fun ((_, ident), _) -> ident)
18131824
flds
18141825
|> List.choose (fun (fld, fldExpr) ->
18151826
try
@@ -1838,7 +1849,7 @@ let BuildFieldMap (cenv: cenv) env isPartial ty (flds: ((Ident list * Ident) * '
18381849
warning (Error(FSComp.SR.tcFieldsDoNotDetermineUniqueRecordType(), m))
18391850

18401851
// try finding a record type with the same number of fields as the ones that are given.
1841-
match tcrefs |> List.tryFind (fun (_, tc) -> tc.TrueFieldsAsList.Length = fldCount) with
1852+
match tcrefs |> List.tryFind (fun (_, tc) -> tc.TrueFieldsAsList.Length = flds.Length) with
18421853
| Some (tinst, tcref) -> tinst, tcref
18431854
| _ ->
18441855
// OK, there isn't a unique, good type dictated by the intersection for the field refs.
@@ -1863,8 +1874,6 @@ let BuildFieldMap (cenv: cenv) env isPartial ty (flds: ((Ident list * Ident) * '
18631874

18641875
CheckFSharpAttributes g fref2.PropertyAttribs ident.idRange |> CommitOperationResult
18651876

1866-
if Map.containsKey fref2.FieldName fs then
1867-
errorR (Error(FSComp.SR.tcFieldAppearsTwiceInRecord(fref2.FieldName), m))
18681877
if showDeprecated then
18691878
let diagnostic = Deprecated(FSComp.SR.nrRecordTypeNeedsQualifiedAccess(fref2.FieldName, fref2.Tycon.DisplayName) |> snd, m)
18701879
if g.langVersion.SupportsFeature(LanguageFeature.ErrorOnDeprecatedRequireQualifiedAccess) then
@@ -8152,7 +8161,7 @@ and TcNameOfExpr (cenv: cenv) env tpenv (synArg: SynExpr) =
81528161

81538162
and TcNameOfExprResult (cenv: cenv) (lastIdent: Ident) m =
81548163
let g = cenv.g
8155-
let constRange = mkRange m.FileName m.Start (mkPos m.StartLine (m.StartColumn + lastIdent.idText.Length + 2)) // `2` are for quotes
8164+
let constRange = withEnd (mkPos m.StartLine (m.StartColumn + lastIdent.idText.Length + 2)) m // `2` are for quotes
81568165
Expr.Const(Const.String(lastIdent.idText), constRange, g.string_ty)
81578166

81588167
//-------------------------------------------------------------------------

src/Compiler/Checking/CheckPatterns.fs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -309,11 +309,6 @@ and TcPat warnOnUpper (cenv: cenv) env valReprInfo vFlags (patEnv: TcPatLinearEn
309309
| SynPat.Record (flds, m) ->
310310
TcRecordPat warnOnUpper cenv env vFlags patEnv ty flds m
311311

312-
| SynPat.DeprecatedCharRange (c1, c2, m) ->
313-
errorR(Deprecated(FSComp.SR.tcUseWhenPatternGuard(), m))
314-
UnifyTypes cenv env m ty g.char_ty
315-
(fun _ -> TPat_range(c1, c2, m)), patEnv
316-
317312
| SynPat.Null m ->
318313
TcNullPat cenv env patEnv ty m
319314

@@ -441,7 +436,7 @@ and TcPatArrayOrList warnOnUpper cenv env vFlags patEnv ty isArray args m =
441436

442437
and TcRecordPat warnOnUpper cenv env vFlags patEnv ty fieldPats m =
443438
let fieldPats = fieldPats |> List.map (fun (fieldId, _, fieldPat) -> fieldId, fieldPat)
444-
match BuildFieldMap cenv env true ty fieldPats m with
439+
match BuildFieldMap cenv env false ty fieldPats m with
445440
| None -> (fun _ -> TPat_error m), patEnv
446441
| Some(tinst, tcref, fldsmap, _fldsList) ->
447442

src/Compiler/Checking/CheckRecordSyntaxHelpers.fs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,14 +79,14 @@ let TransformAstForNestedUpdates (cenv: TcFileState) (env: TcEnv) overallTy (lid
7979
| [ _ ] -> [ origSepRng ]
8080
| _ :: t ->
8181
origSepRng
82-
:: List.map (fun (s: Ident, e: Ident) -> mkRange s.idRange.FileName s.idRange.End e.idRange.Start) t
82+
:: List.map (fun (s: Ident, e: Ident) -> withStartEnd s.idRange.End e.idRange.Start s.idRange) t
8383

8484
let lid = buildLid [] id lidwd |> List.rev
8585

8686
(lid, List.pairwise lid |> calcLidSeparatorRanges origSepRng)
8787

8888
let totalRange (origId: Ident) (id: Ident) =
89-
mkRange origId.idRange.FileName origId.idRange.End id.idRange.Start
89+
withStartEnd origId.idRange.End id.idRange.Start origId.idRange
9090

9191
let rangeOfBlockSeperator (id: Ident) =
9292
let idEnd = id.idRange.End
@@ -95,7 +95,7 @@ let TransformAstForNestedUpdates (cenv: TcFileState) (env: TcEnv) overallTy (lid
9595
let blockSeperatorStartPos = mkPos idEnd.Line blockSeperatorStartCol
9696
let blockSeporatorEndPos = mkPos idEnd.Line blockSeperatorEndCol
9797

98-
mkRange id.idRange.FileName blockSeperatorStartPos blockSeporatorEndPos
98+
withStartEnd blockSeperatorStartPos blockSeporatorEndPos id.idRange
9999

100100
match withExpr with
101101
| SynExpr.Ident origId, (sepRange, _) ->

src/Compiler/Checking/PatternMatchCompilation.fs

Lines changed: 37 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ open FSharp.Compiler.TypedTreeBasics
2323
open FSharp.Compiler.TypedTreeOps
2424
open FSharp.Compiler.TypedTreeOps.DebugPrint
2525
open FSharp.Compiler.TypeRelations
26+
open type System.MemoryExtensions
2627

2728
exception MatchIncomplete of bool * (string * bool) option * range
2829
exception RuleNeverMatched of range
@@ -48,7 +49,6 @@ type Pattern =
4849
| TPat_tuple of TupInfo * Pattern list * TType list * range
4950
| TPat_array of Pattern list * TType * range
5051
| TPat_recd of TyconRef * TypeInst * Pattern list * range
51-
| TPat_range of char * char * range
5252
| TPat_null of range
5353
| TPat_isinst of TType * TType * Pattern option * range
5454
| TPat_error of range
@@ -66,7 +66,6 @@ type Pattern =
6666
| TPat_tuple(_, _, _, m) -> m
6767
| TPat_array(_, _, m) -> m
6868
| TPat_recd(_, _, _, m) -> m
69-
| TPat_range(_, _, m) -> m
7069
| TPat_null m -> m
7170
| TPat_isinst(_, _, _, m) -> m
7271
| TPat_error m -> m
@@ -720,7 +719,7 @@ let discrimWithinSimultaneousClass g amap m discrim prev =
720719
let canInvestigate (pat: Pattern) =
721720
match pat with
722721
| TPat_null _ | TPat_isinst _ | TPat_exnconstr _ | TPat_unioncase _
723-
| TPat_array _ | TPat_const _ | TPat_query _ | TPat_range _ | TPat_error _ -> true
722+
| TPat_array _ | TPat_const _ | TPat_query _ | TPat_error _ -> true
724723
| _ -> false
725724

726725
/// Decide the next pattern to investigate
@@ -905,43 +904,37 @@ let rec layoutPat pat =
905904
let mkFrontiers investigations clauseNumber =
906905
investigations |> List.map (fun (actives, valMap) -> Frontier(clauseNumber, actives, valMap))
907906

907+
let singleFalseInvestigationPoint = [| false |]
908+
908909
// Search for pattern decision points that are decided "one at a time" - i.e. where there is no
909910
// multi-way switching. For example partial active patterns
910911
let rec investigationPoints inpPat =
911-
seq {
912-
match inpPat with
913-
| TPat_query ((_, _, _, _, _, apinfo), subPat, _) ->
914-
yield not apinfo.IsTotal
915-
yield! investigationPoints subPat
916-
| TPat_isinst (_, _tgtTy, subPatOpt, _) ->
917-
yield false
918-
match subPatOpt with
919-
| None -> ()
920-
| Some subPat ->
921-
yield! investigationPoints subPat
922-
| TPat_as (subPat, _, _) ->
923-
yield! investigationPoints subPat
924-
| TPat_disjs (subPats, _)
925-
| TPat_conjs(subPats, _)
926-
| TPat_tuple (_, subPats, _, _)
927-
| TPat_recd (_, _, subPats, _) ->
928-
for subPat in subPats do
929-
yield! investigationPoints subPat
930-
| TPat_exnconstr(_, subPats, _) ->
931-
for subPat in subPats do
932-
yield! investigationPoints subPat
933-
| TPat_array (subPats, _, _)
934-
| TPat_unioncase (_, _, subPats, _) ->
935-
yield false
936-
for subPat in subPats do
937-
yield! investigationPoints subPat
938-
| TPat_range _
939-
| TPat_null _
940-
| TPat_const _ ->
941-
yield false
942-
| TPat_wild _
943-
| TPat_error _ -> ()
944-
}
912+
match inpPat with
913+
| TPat_query((_, _, _, _, _, apinfo), subPat, _) ->
914+
Array.prepend (not apinfo.IsTotal) (investigationPoints subPat)
915+
| TPat_isinst(_, _tgtTy, subPatOpt, _) ->
916+
match subPatOpt with
917+
| None -> singleFalseInvestigationPoint
918+
| Some subPat -> Array.prepend false (investigationPoints subPat)
919+
| TPat_as(subPat, _, _) -> investigationPoints subPat
920+
| TPat_disjs(subPats, _)
921+
| TPat_conjs(subPats, _)
922+
| TPat_tuple(_, subPats, _, _)
923+
| TPat_exnconstr(_, subPats, _)
924+
| TPat_recd(_, _, subPats, _) ->
925+
subPats
926+
|> Seq.collect investigationPoints
927+
|> Seq.toArray
928+
| TPat_array (subPats, _, _)
929+
| TPat_unioncase (_, _, subPats, _) ->
930+
subPats
931+
|> Seq.collect investigationPoints
932+
|> Seq.toArray
933+
|> Array.prepend false
934+
| TPat_null _
935+
| TPat_const _ -> singleFalseInvestigationPoint
936+
| TPat_wild _
937+
| TPat_error _ -> [||]
945938

946939
let rec erasePartialPatterns inpPat =
947940
match inpPat with
@@ -959,7 +952,6 @@ let rec erasePartialPatterns inpPat =
959952
| TPat_isinst (x, y, subPatOpt, m) -> TPat_isinst (x, y, Option.map erasePartialPatterns subPatOpt, m)
960953
| TPat_const _
961954
| TPat_wild _
962-
| TPat_range _
963955
| TPat_null _
964956
| TPat_error _ -> inpPat
965957

@@ -1002,7 +994,6 @@ let rec isPatternDisjunctive inpPat =
1002994
| TPat_isinst (_, _, subPatOpt, _) -> Option.exists isPatternDisjunctive subPatOpt
1003995
| TPat_const _ -> false
1004996
| TPat_wild _ -> false
1005-
| TPat_range _ -> false
1006997
| TPat_null _ -> false
1007998
| TPat_error _ -> false
1008999

@@ -1605,8 +1596,6 @@ let CompilePatternBasic
16051596
| _ ->
16061597
[frontier]
16071598

1608-
| _ -> failwith "pattern compilation: GenerateNewFrontiersAfterSuccessfulInvestigation"
1609-
16101599
else
16111600
[frontier]
16121601

@@ -1646,12 +1635,6 @@ let CompilePatternBasic
16461635
let newActives = List.mapi (mkSubActive (fun path _j -> path) (fun _j -> inpAccess)) subPats
16471636
BindProjectionPatterns newActives activeState
16481637

1649-
| TPat_range (c1, c2, m) ->
1650-
let mutable res = []
1651-
for i = int c1 to int c2 do
1652-
res <- BindProjectionPattern (Active(inpPath, inpExpr, TPat_const(Const.Char(char i), m))) activeState @ res
1653-
res
1654-
16551638
// Assign an identifier to each TPat_query based on our knowledge of the 'identity' of the active pattern, if any
16561639
| TPat_query ((_, _, _, apatVrefOpt, _, _), _, _) ->
16571640
let uniqId =
@@ -1740,16 +1723,13 @@ let CompilePatternBasic
17401723
// So disjunction alone isn't considered problematic, but in combination with 'when' patterns
17411724

17421725
let isProblematicClause (clause: MatchClause) =
1743-
let ips =
1744-
seq {
1745-
yield! investigationPoints clause.Pattern
1746-
if clause.GuardExpr.IsSome then
1747-
yield true
1748-
} |> Seq.toArray
1749-
let ips = if isPatternDisjunctive clause.Pattern then Array.append ips ips else ips
1750-
// Look for multiple decision points.
1751-
// We don't mind about the last logical decision point
1752-
ips.Length > 0 && Array.exists id ips[0..ips.Length-2]
1726+
if clause.GuardExpr.IsSome then
1727+
isPatternDisjunctive clause.Pattern || Array.exists id (investigationPoints clause.Pattern)
1728+
else
1729+
// Look for multiple decision points.
1730+
// We don't mind about the last logical decision point
1731+
let ips = investigationPoints clause.Pattern
1732+
ips.Length > 0 && Span.exists id (ips.AsSpan (0, ips.Length - 1))
17531733

17541734
let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) (clausesL: MatchClause list) inputTy resultTy =
17551735
match clausesL with

src/Compiler/Checking/PatternMatchCompilation.fsi

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ type Pattern =
3333
| TPat_tuple of TupInfo * Pattern list * TType list * range
3434
| TPat_array of Pattern list * TType * range
3535
| TPat_recd of TyconRef * TypeInst * Pattern list * range
36-
| TPat_range of char * char * range
3736
| TPat_null of range
3837
| TPat_isinst of TType * TType * Pattern option * range
3938
| TPat_error of range

0 commit comments

Comments
 (0)