Skip to content

Commit

Permalink
Lets try this version
Browse files Browse the repository at this point in the history
  • Loading branch information
edgarfgp committed Jul 6, 2024
1 parent 1f3c5ac commit e81303d
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 35 deletions.
7 changes: 0 additions & 7 deletions src/Compiler/Checking/CheckComputationExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3454,13 +3454,6 @@ let TcSequenceExpressionEntry (cenv: cenv) env (overallTy: OverallTy) tpenv (has
let validateObjectSequenceOrRecordExpression = not implicitYieldEnabled

match comp with
| SynExpr.New _ ->
try
TcExprUndelayed cenv overallTy env tpenv comp |> ignore
with RecoverableException e ->
errorRecovery e m

errorR (Error(FSComp.SR.tcInvalidObjectExpressionSyntaxForm (), m))
| SimpleSemicolonSequence cenv false _ when validateObjectSequenceOrRecordExpression ->
errorR (Error(FSComp.SR.tcInvalidObjectSequenceOrRecordExpression (), m))
| _ -> ()
Expand Down
45 changes: 28 additions & 17 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -6793,8 +6793,8 @@ and TcRecordConstruction (cenv: cenv) (overallTy: TType) isObjExpr env tpenv wit
UnifyTypes cenv env m overallTy objTy

// Types with implicit constructors can't use record or object syntax: all constructions must go through the implicit constructor
let supportsObjectExpressionWithoutOverrides = isObjExpr && g.langVersion.SupportsFeature(LanguageFeature.AllowObjectExpressionWithoutOverrides)
if tycon.MembersOfFSharpTyconByName |> NameMultiMap.existsInRange (fun v -> v.IsIncrClassConstructor) && not supportsObjectExpressionWithoutOverrides then
// let supportsObjectExpressionWithoutOverrides = isObjExpr && g.langVersion.SupportsFeature(LanguageFeature.AllowObjectExpressionWithoutOverrides)
if tycon.MembersOfFSharpTyconByName |> NameMultiMap.existsInRange (fun v -> v.IsIncrClassConstructor) then
errorR(Error(FSComp.SR.tcConstructorRequiresCall(tycon.DisplayName), m))

let fspecs = tycon.TrueInstanceFieldsAsList
Expand Down Expand Up @@ -7159,8 +7159,11 @@ and TcObjectExpr (cenv: cenv) env tpenv (objTy, realObjTy, argopt, binds, extraI

if argopt.IsSome then error(Error(FSComp.SR.tcNoArgumentsForRecordValue(), mWholeExpr))
if not (isNil extraImpls) then error(Error(FSComp.SR.tcNoInterfaceImplementationForConstructionExpression(), mNewExpr))
let supportsObjectExpressionWithoutOverrides = g.langVersion.SupportsFeature(LanguageFeature.AllowObjectExpressionWithoutOverrides)
if isFSharpObjModelTy g objTy && GetCtorShapeCounter env <> 1 && not supportsObjectExpressionWithoutOverrides then
// let supportsObjectExpressionWithoutOverrides = g.langVersion.SupportsFeature(LanguageFeature.AllowObjectExpressionWithoutOverrides)


let requiresConstructor = GetCtorShapeCounter env <> 1
if isFSharpObjModelTy g objTy && requiresConstructor then
error(Error(FSComp.SR.tcObjectConstructionCanOnlyBeUsedInClassTypes(), mNewExpr))
let fldsList =
binds |> List.map (fun b ->
Expand Down Expand Up @@ -7207,19 +7210,27 @@ and TcObjectExpr (cenv: cenv) env tpenv (objTy, realObjTy, argopt, binds, extraI

let overridesAndVirts, tpenv = ComputeObjectExprOverrides cenv env tpenv impls

// 2. check usage conditions
overridesAndVirts |> List.iter (fun (m, implTy, dispatchSlots, dispatchSlotsKeyed, availPriorOverrides, overrides) ->
// 2. check usage conditions
for ovd in overridesAndVirts do
let (m, implTy, dispatchSlots, dispatchSlotsKeyed, availPriorOverrides, overrides) = ovd
let overrideSpecs = overrides |> List.map fst
let hasStaticMembers = dispatchSlots |> List.exists (fun reqdSlot -> not reqdSlot.MethodInfo.IsInstance)

let isAbstractClass =
match tryTcrefOfAppTy g objTy with
| ValueNone -> false
| ValueSome tcref -> HasFSharpAttribute g g.attrib_AbstractClassAttribute tcref.Attribs

if overrideSpecs.IsEmpty && not isAbstractClass && not (isInterfaceTy g objTy) then
errorR (Error(FSComp.SR.tcInvalidObjectExpressionSyntaxForm (), mObjTy))

if hasStaticMembers then
errorR(Error(FSComp.SR.chkStaticMembersOnObjectExpressions(), mObjTy))

DispatchSlotChecking.CheckOverridesAreAllUsedOnce (env.DisplayEnv, g, cenv.infoReader, true, implTy, dispatchSlotsKeyed, availPriorOverrides, overrideSpecs)

if not hasStaticMembers then
if not hasStaticMembers && not isAbstractClass then
DispatchSlotChecking.CheckDispatchSlotsAreImplemented (env.DisplayEnv, cenv.infoReader, m, env.NameEnv, cenv.tcSink, false, implTy, dispatchSlots, availPriorOverrides, overrideSpecs) |> ignore
)


// 3. create the specs of overrides
let allTypeImpls =
Expand Down Expand Up @@ -10787,14 +10798,14 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt
match rhsExpr with
| SynExpr.Fixed (e, _) -> true, e, NewInferenceType g, overallTy
| e ->
let supportsObjectExpressionWithoutOverrides = g.langVersion.SupportsFeature(LanguageFeature.AllowObjectExpressionWithoutOverrides)
if supportsObjectExpressionWithoutOverrides then
match e with
| SynExpr.ComputationExpr(false, SynExpr.New(_, targetType, _, m), _) ->
false, SynExpr.ObjExpr(targetType, None, None, [], [], [], m, rhsExpr.Range), NewInferenceType g, overallTy
| _ -> false, e, overallTy, overallTy
else
false, e, overallTy, overallTy
// let supportsObjectExpressionWithoutOverrides = g.langVersion.SupportsFeature(LanguageFeature.AllowObjectExpressionWithoutOverrides)
// if supportsObjectExpressionWithoutOverrides then
match e with
| SynExpr.ComputationExpr(false, SynExpr.New(_, targetType, expr, m), _) ->
false, SynExpr.ObjExpr(targetType, Some(expr, None), None, [], [], [], m, rhsExpr.Range), overallTy, overallTy
| _ -> false, e, overallTy, overallTy
//else
// false, e, overallTy, overallTy

// Check the attributes of the binding, parameters or return value
let TcAttrs tgt isRet attrs =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,36 +58,46 @@ let implSomeDU someDu =
|> shouldSucceed

[<Fact>]
let ``Object expression can not implement an abstract class having no abstract members.`` () =
let ``Object expression can implement an abstract class having no abstract members.`` () =
Fsx """
[<AbstractClass>]
type Foo() = class end
let foo = { new Foo() } // Approved suggestion to allow this https://github.com/fsharp/fslang-suggestions/issues/632
let foo = { new Foo() }
// hacky workaround
let foo1 = { new Foo() with member __.ToString() = base.ToString() }
"""
|> withLangVersion80
|> typecheck
|> shouldSucceed

[<Fact>]
let ``Error when using an object expression with a none abstract class`` () =
Fsx """
type MyClass() = class end
let foo = { new MyClass() }
"""
|> withLangVersion80
|> typecheck
|> shouldFail
|> withDiagnostics [
(Error 759, Line 5, Col 13, Line 5, Col 22, "Instances of this type cannot be created since it has been marked abstract or not all methods have been given implementations. Consider using an object expression '{ new ... with ... }' instead.");
(Error 738, Line 5, Col 11, Line 5, Col 24, "Invalid object expression. Objects without overrides or interfaces should use the expression form 'new Type(args)' without braces.")
(Error 740, Line 5, Col 11, Line 5, Col 24, "Invalid record, sequence or computation expression. Sequence expressions should be of the form 'seq { ... }'")
(Error 738, Line 4, Col 17, Line 4, Col 24, "Invalid object expression. Objects without overrides or interfaces should use the expression form 'new Type(args)' without braces.")
]

[<Fact>]
let ``Object expression can implement an abstract class having no abstract members.`` () =
let ``No Error when object expression does not implement all abstract members of an abstract class`` () =
Fsx """
[<AbstractClass>]
type Foo() = class end
type MyAbstractClass() =
abstract Bar: unit -> unit
let foo = { new Foo() }
let foo = { new MyAbstractClass() }
let foo1 = { new Foo() with member __.ToString() = base.ToString() }
"""
|> withLangVersionPreview
|> withLangVersion80
|> typecheck
|> shouldSucceed

Expand Down

0 comments on commit e81303d

Please sign in to comment.