Skip to content

Commit

Permalink
Checker: fix exception on wrong update syntax in anon records (#15638)
Browse files Browse the repository at this point in the history
  • Loading branch information
auduchinok authored Jul 19, 2023
1 parent 67dd8f6 commit 0f893c3
Show file tree
Hide file tree
Showing 9 changed files with 524 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 @@ -1809,10 +1809,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 @@ -1872,7 +1879,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 @@ -7370,7 +7377,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 @@ -7386,7 +7396,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 @@ -7401,7 +7411,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 @@ -7419,14 +7429,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 @@ -74,4 +74,17 @@ module NestedAnonRecds
let x = {| abcd = {| ab = 4; cd = 1 |} |}
"""
|> compile
|> shouldSucceed
|> 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 0f893c3

Please sign in to comment.