Skip to content

Commit

Permalink
Checker: fix exception on wrong update syntax in anon records (dotnet…
Browse files Browse the repository at this point in the history
  • Loading branch information
auduchinok authored and vzarytovskii committed Jul 25, 2023
1 parent 30bbce6 commit 2b15585
Show file tree
Hide file tree
Showing 9 changed files with 534 additions and 25 deletions.
44 changes: 29 additions & 15 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1807,10 +1807,17 @@ let BuildFieldMap (cenv: cenv) env isPartial ty (flds: ((Ident list * Ident) * '
let fldResolutions =
let allFields = flds |> List.map (fun ((_, ident), _) -> ident)
flds
|> List.map (fun (fld, fldExpr) ->
let (fldPath, fldId) = fld
let frefSet = ResolveField cenv.tcSink cenv.nameResolver env.eNameResEnv ad ty fldPath fldId allFields
fld, frefSet, fldExpr)
|> List.choose (fun (fld, fldExpr) ->
try
let fldPath, fldId = fld
let frefSet = ResolveField cenv.tcSink cenv.nameResolver env.eNameResEnv ad ty fldPath fldId allFields
Some(fld, frefSet, fldExpr)
with e ->
errorRecoveryNoRange e
None
)

if fldResolutions.IsEmpty then None else

let relevantTypeSets =
fldResolutions |> List.map (fun (_, frefSet, _) ->
Expand Down Expand Up @@ -1870,7 +1877,7 @@ let BuildFieldMap (cenv: cenv) env isPartial ty (flds: ((Ident list * Ident) * '
Map.add fref2.FieldName fldExpr fs, (fref2.FieldName, fldExpr) :: rfldsList

| _ -> error(Error(FSComp.SR.tcRecordFieldInconsistentTypes(), m)))
tinst, tcref, fldsmap, List.rev rfldsList
Some(tinst, tcref, fldsmap, List.rev rfldsList)

let rec ApplyUnionCaseOrExn (makerForUnionCase, makerForExnTag) m (cenv: cenv) env overallTy item =
let g = cenv.g
Expand Down Expand Up @@ -7366,7 +7373,10 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, withExprOpt, synRecdFields, m
match flds with
| [] -> []
| _ ->
let tinst, tcref, _, fldsList = BuildFieldMap cenv env hasOrigExpr overallTy flds mWholeExpr
match BuildFieldMap cenv env hasOrigExpr overallTy flds mWholeExpr with
| None -> []
| Some(tinst, tcref, _, fldsList) ->

let gtyp = mkAppTy tcref tinst
UnifyTypes cenv env mWholeExpr overallTy gtyp

Expand All @@ -7382,7 +7392,7 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, withExprOpt, synRecdFields, m
let withExprAddrVal, withExprAddrValExpr = mkCompGenLocal mWholeExpr "inputRecord" (if isStructTy g overallTy then mkByrefTy g overallTy else overallTy)
Some(withExpr, withExprAddrVal, withExprAddrValExpr)

if hasOrigExpr && not (isRecdTy g overallTy) then
if hasOrigExpr && not (isRecdTy g overallTy || isAnonRecdTy g overallTy) then
errorR(Error(FSComp.SR.tcExpressionFormRequiresRecordTypes(), mWholeExpr))

if requiresCtor || haveCtor then
Expand All @@ -7397,7 +7407,7 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, withExprOpt, synRecdFields, m
error(Error(errorInfo, mWholeExpr))

if isFSharpObjModelTy g overallTy then errorR(Error(FSComp.SR.tcTypeIsNotARecordTypeNeedConstructor(), mWholeExpr))
elif not (isRecdTy g overallTy) then errorR(Error(FSComp.SR.tcTypeIsNotARecordType(), mWholeExpr))
elif not (isRecdTy g overallTy || fldsList.IsEmpty) then errorR(Error(FSComp.SR.tcTypeIsNotARecordType(), mWholeExpr))

let superInitExprOpt , tpenv =
match inherits, GetSuperTypeOfType g cenv.amap mWholeExpr overallTy with
Expand All @@ -7415,14 +7425,18 @@ and TcRecdExpr cenv overallTy env tpenv (inherits, withExprOpt, synRecdFields, m
errorR(InternalError("Unexpected failure in getting super type", mWholeExpr))
None, tpenv

let expr, tpenv = TcRecordConstruction cenv overallTy env tpenv withExprInfoOpt overallTy fldsList mWholeExpr
if fldsList.IsEmpty && isTyparTy g overallTy || isAnonRecdTy g overallTy then
SolveTypeAsError env.DisplayEnv cenv.css mWholeExpr overallTy
mkDefault (mWholeExpr, overallTy), tpenv
else
let expr, tpenv = TcRecordConstruction cenv overallTy env tpenv withExprInfoOpt overallTy fldsList mWholeExpr

let expr =
match superInitExprOpt with
| _ when isStructTy g overallTy -> expr
| Some superInitExpr -> mkCompGenSequential mWholeExpr superInitExpr expr
| None -> expr
expr, tpenv
let expr =
match superInitExprOpt with
| _ when isStructTy g overallTy -> expr
| Some superInitExpr -> mkCompGenSequential mWholeExpr superInitExpr expr
| None -> expr
expr, tpenv


// Check '{| .... |}'
Expand Down
2 changes: 1 addition & 1 deletion src/Compiler/Checking/CheckExpressions.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -895,7 +895,7 @@ val BuildFieldMap:
ty: TType ->
flds: ((Ident list * Ident) * 'T) list ->
m: range ->
TypeInst * TyconRef * Map<string, 'T> * (string * 'T) list
(TypeInst * TyconRef * Map<string, 'T> * (string * 'T) list) option

/// Check a long identifier 'Case' or 'Case argsR' that has been resolved to an active pattern case
val TcPatLongIdentActivePatternCase:
Expand Down
5 changes: 4 additions & 1 deletion src/Compiler/Checking/CheckPatterns.fs
Original file line number Diff line number Diff line change
Expand Up @@ -441,7 +441,10 @@ and TcPatArrayOrList warnOnUpper cenv env vFlags patEnv ty isArray args m =

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

let gtyp = mkAppTy tcref tinst
let inst = List.zip (tcref.Typars m) tinst

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,27 @@ 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."
]
]

[<Fact>]
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

[<Fact>]
let ``Wrong update syntax`` () =
Fsx """
let f (r: {| A: int |}) =
{ r with A = 1 }
"""
|> ignoreWarnings
|> compile
|> shouldFail
|> withDiagnostics [
(Error 39, Line 3, Col 14, Line 3, Col 15, "The record label 'A' is not defined.")
]
Loading

0 comments on commit 2b15585

Please sign in to comment.