@@ -8065,7 +8065,93 @@ and TcNewAnonRecdExpr cenv (overallTy: TType) env tpenv (isStruct, unsortedField
80658065
80668066 let maybeAnonRecdTargetTy = tryDestAnonRecdTy g overallTy
80678067
8068+ let possibleTargetTyAt =
8069+ match maybeAnonRecdTargetTy with
8070+ | ValueSome (anonInfo, tys) ->
8071+ let names = anonInfo.SortedNames
8072+ let tys = List.toArray tys
8073+ fun name ->
8074+ let i = Array.BinarySearch (names, name)
8075+ if i < 0 then ValueNone
8076+ else ValueSome tys[i]
8077+ | ValueNone -> fun _ -> ValueNone
8078+
80688079 let spreadSrcs, unsortedCheckedFields, sortedCheckedFields, tpenv =
8080+ let (|LeftwardExplicit|NoLeftwardExplicit|) hasLeftwardExplicit = if hasLeftwardExplicit then LeftwardExplicit else NoLeftwardExplicit
8081+ let LeftwardExplicit = true
8082+ let NoLeftwardExplicit = false
8083+
8084+ let rec mkTcFuncs tys i fieldsAndSpreads =
8085+ match fieldsAndSpreads with
8086+ | [] ->
8087+ let acc =
8088+ (Map.empty, tys) ||> Map.fold (fun acc _ (_, tys) ->
8089+ let (i, ty), tys = List.headAndTail tys
8090+ let acc = acc |> Map.add i (fun _ expr tpenv -> ty, TcExprFlex cenv true false ty env tpenv expr)
8091+ (acc, tys) ||> List.fold (fun acc (i, ty) -> acc |> Map.add i (fun m _ tpenv -> ty, (mkThrow m ty (mkOne g m), tpenv))))
8092+
8093+ fun i m expr tpenv ->
8094+ acc
8095+ |> Map.tryFind i
8096+ |> Option.map (fun tc -> tc m expr tpenv)
8097+ |> Option.defaultWith (fun () -> g.obj_ty_ambivalent, (mkThrow m g.obj_ty_ambivalent (mkOne g m), tpenv))
8098+
8099+ | SynExprAnonRecordFieldOrSpread.Field (SynExprAnonRecordField (fieldName = SynLongIdent (([] | _ :: _ :: _), _, _); range = m), _) :: _ ->
8100+ error (InternalError ("All field names should have been transformed into simple identifiers by this point.", m))
8101+
8102+ // Explicitly redeclared fields are not allowed:
8103+ // {| A = 3; A = 4 |}
8104+ // ↑ error FS3522
8105+ | SynExprAnonRecordFieldOrSpread.Field (SynExprAnonRecordField (fieldName = SynLongIdent ([fieldId], _, _)), _) :: fieldsAndSpreads ->
8106+ let ty = possibleTargetTyAt fieldId.idText |> ValueOption.defaultWith (fun () -> NewInferenceType g)
8107+
8108+ let tys =
8109+ tys |> Map.change fieldId.idText (function
8110+ | None -> Some (LeftwardExplicit, [i, ty])
8111+ | Some (LeftwardExplicit, dupes) -> Some (LeftwardExplicit, (i, ty) :: dupes)
8112+ | Some (NoLeftwardExplicit, _dupes) -> Some (LeftwardExplicit, [i, ty]))
8113+
8114+ mkTcFuncs tys (i + 1) fieldsAndSpreads
8115+
8116+ // Field shadowing from spreads is allowed:
8117+ // let a = {| A = 3 |}
8118+ // let b = {| A = "4" |}
8119+ // let c = {| ...a; ...b |} → {| A = "4" |}
8120+ | SynExprAnonRecordFieldOrSpread.Spread (SynExprSpread (expr = expr; range = m), _) :: fieldsAndSpreads ->
8121+ checkLanguageFeatureAndRecover g.langVersion LanguageFeature.RecordSpreads m
8122+
8123+ let flex = false
8124+ let spreadSrcExpr, _ = TcExprFlex cenv flex false (NewInferenceType g) env tpenv expr
8125+ let tyOfSpreadSrcExpr = tyOfExpr g spreadSrcExpr
8126+
8127+ let fieldsFromSpread =
8128+ if isRecdTy g tyOfSpreadSrcExpr then
8129+ ResolveRecordOrClassFieldsOfType cenv.nameResolver m ad tyOfSpreadSrcExpr false
8130+ |> List.choose (function
8131+ | Item.RecdField field ->
8132+ let fieldId = field.RecdField.Id.idText
8133+ Some (fieldId, possibleTargetTyAt fieldId |> ValueOption.defaultValue field.FieldType)
8134+ | _ -> None)
8135+ else
8136+ match tryDestAnonRecdTy g tyOfSpreadSrcExpr with
8137+ | ValueSome (anonInfo, tys) ->
8138+ tys |> List.mapi (fun j ty ->
8139+ let fieldId = anonInfo.SortedNames[j]
8140+ fieldId, possibleTargetTyAt fieldId |> ValueOption.defaultValue ty)
8141+ | ValueNone -> []
8142+
8143+ let i, tys =
8144+ ((i, tys), fieldsFromSpread)
8145+ ||> List.fold (fun (i, tys) (fieldId, ty) ->
8146+ i + 1, tys |> Map.change fieldId (function
8147+ | None -> Some (NoLeftwardExplicit, [i, ty])
8148+ | Some (LeftwardExplicit, _dupes) -> Some (LeftwardExplicit, [i, ty])
8149+ | Some (NoLeftwardExplicit, _dupes) -> Some (NoLeftwardExplicit, [i, ty])))
8150+
8151+ mkTcFuncs tys i fieldsAndSpreads
8152+
8153+ let targetTys = mkTcFuncs Map.empty 0 unsortedFieldIdsAndSynExprsGiven
8154+
80698155 let rec tcFieldsAndSpreads spreadSrcs checkedFields i tpenv fieldsAndSpreads =
80708156 let (|LeftwardExplicit|NoLeftwardExplicit|) hasLeftwardExplicit = if hasLeftwardExplicit then LeftwardExplicit else NoLeftwardExplicit
80718157 let LeftwardExplicit = true
@@ -8105,9 +8191,7 @@ and TcNewAnonRecdExpr cenv (overallTy: TType) env tpenv (isStruct, unsortedField
81058191 // {| A = 3; A = 4 |}
81068192 // ↑ error FS3522
81078193 | SynExprAnonRecordFieldOrSpread.Field (SynExprAnonRecordField (fieldName = SynLongIdent ([fieldId], _, _); expr = expr; range = m), _) :: fieldsAndSpreads ->
8108- let flex = true
8109- let ty = NewInferenceType g
8110- let expr, tpenv = TcExprFlex cenv flex false ty env tpenv expr
8194+ let ty, (expr, tpenv) = targetTys i m expr tpenv
81118195
81128196 let checkedFields =
81138197 checkedFields |> Map.change fieldId.idText (function
@@ -8164,7 +8248,7 @@ and TcNewAnonRecdExpr cenv (overallTy: TType) env tpenv (isStruct, unsortedField
81648248 | Item.RecdField fieldInfo :: fieldsFromSpread ->
81658249 let fieldExpr = mkRecdFieldGetViaExprAddr (spreadSrcAddrExpr, fieldInfo.RecdFieldRef, fieldInfo.TypeInst, m)
81668250 let fieldId = fieldInfo.RecdFieldRef.RecdField.Id
8167- let ty = fieldInfo.FieldType
8251+ let ty = possibleTargetTyAt fieldId.idText |> ValueOption.defaultValue fieldInfo.FieldType
81688252
81698253 let checkedFields =
81708254 checkedFields |> Map.change fieldId.idText (function
@@ -8261,20 +8345,18 @@ and TcNewAnonRecdExpr cenv (overallTy: TType) env tpenv (isStruct, unsortedField
82618345 let anonInfo, sortedFieldTys =
82628346 let anonInfo, sortedFieldTys =
82638347 match maybeAnonRecdTargetTy with
8264- | ValueSome (anonInfo, ptys ) ->
8348+ | ValueSome (anonInfo, _ ) ->
82658349 // Note: use the assembly of the known type, not the current assembly
82668350 // Note: use the structness of the known type, unless explicit
82678351 // Note: use the names of our type, since they are always explicit
82688352 let tupInfo = if isStruct then tupInfoStruct else anonInfo.TupInfo
82698353 let anonInfo = AnonRecdTypeInfo.Create(anonInfo.Assembly, tupInfo, sortedNames)
82708354 let sortedFieldTys =
8271- if List.length ptys = sortedNames.Length then ptys
8272- else
8273- [
8274- for KeyValue (_, (_, dupes)) in sortedCheckedFields do
8275- for _, _, ty, _ in dupes do
8276- ty
8277- ]
8355+ [
8356+ for KeyValue (_, (_, dupes)) in sortedCheckedFields do
8357+ for _, _, ty, _ in dupes do
8358+ ty
8359+ ]
82788360 anonInfo, sortedFieldTys
82798361 | ValueNone ->
82808362 // Note: no known anonymous record type - use our assembly
0 commit comments