Skip to content

Commit

Permalink
Fixed type abbreviation from bypassing ByRefLike rules (dotnet#7953)
Browse files Browse the repository at this point in the history
* Trying to fix span type abbrev

* Fixed type abbrev issue on span

* Fixing build

* Update test

* Apply suggestions from code review

I like @cartermps test name changes.

Co-Authored-By: Phillip Carter <pcarter@fastmail.com>

* Update PostInferenceChecks.fs
  • Loading branch information
TIHan authored and nosami committed Feb 22, 2021
1 parent d071e26 commit efccc97
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 4 deletions.
11 changes: 9 additions & 2 deletions src/fsharp/PostInferenceChecks.fs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ let RecordAnonRecdInfo cenv (anonInfo: AnonRecdTypeInfo) =
// approx walk of type
//--------------------------------------------------------------------------

let rec CheckTypeDeep (cenv: cenv) ((visitTy, visitTyconRefOpt, visitAppTyOpt, visitTraitSolutionOpt, visitTyparOpt) as f) g env isInner ty =
let rec CheckTypeDeep (cenv: cenv) ((visitTy, visitTyconRefOpt, visitAppTyOpt, visitTraitSolutionOpt, visitTyparOpt) as f) (g: TcGlobals) env isInner ty =
// We iterate the _solved_ constraints as well, to pick up any record of trait constraint solutions
// This means we walk _all_ the constraints _everywhere_ in a type, including
// those attached to _solved_ type variables. This is used by PostTypeCheckSemanticChecks to detect uses of
Expand All @@ -332,7 +332,14 @@ let rec CheckTypeDeep (cenv: cenv) ((visitTy, visitTyconRefOpt, visitAppTyOpt, v
| _ -> ())
| _ -> ()

let ty = stripTyparEqns ty
let ty =
if g.compilingFslib then
match stripTyparEqns ty with
// When compiling FSharp.Core, do not strip type equations at this point if we can't dereference a tycon.
| TType_app (tcref, _) when not tcref.CanDeref -> ty
| _ -> stripTyEqns g ty
else
stripTyEqns g ty
visitTy ty

match ty with
Expand Down
2 changes: 1 addition & 1 deletion tests/fsharp/Compiler/CompilerAssert.fs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ let main argv = 0"""
typeCheckResults.Errors
|> Array.distinctBy (fun e -> e.Severity, e.ErrorNumber, e.StartLineAlternate, e.StartColumn, e.EndLineAlternate, e.EndColumn, e.Message)

Assert.AreEqual(Array.length expectedTypeErrors, errors.Length, sprintf "Type check errors: %A" typeCheckResults.Errors)
Assert.AreEqual(Array.length expectedTypeErrors, errors.Length, sprintf "Type check errors: %A" errors)

Array.zip errors expectedTypeErrors
|> Array.iter (fun (info, expectedError) ->
Expand Down
54 changes: 53 additions & 1 deletion tests/fsharp/Compiler/Language/SpanTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace FSharp.Compiler.UnitTests

open System
open FSharp.Compiler.SourceCodeServices
open NUnit.Framework

#if NETCOREAPP
Expand Down Expand Up @@ -50,4 +51,55 @@ test ()
// We expect this error until System.Reflection.Emit gets fixed for emitting `modreq` on method calls.
// See: https://github.com/dotnet/corefx/issues/29254
CompilerAssert.RunScript script [ "Method not found: '!0 ByRef System.ReadOnlySpan`1.get_Item(Int32)'." ]
#endif


[<Test>]
let ``Invalid usage of type abbreviated span should fail to compile``() =
CompilerAssert.TypeCheckWithErrors """
open System
type Bytes = ReadOnlySpan<byte>
type Test() =
member _.M1 (data: Bytes) =
let x =
if false then
failwith ""
else
data
x
member _.M2 (data: Bytes) =
let x =
if false then
failwithf ""
else
data
x
let test () =
let span = ReadOnlySpan<_>(Array.empty)
let result = Test().M1(span)
let result = Test().M2(span)
0
"""
[|
FSharpErrorSeverity.Error, 412, (11, 17, 11, 28), "A type instantiation involves a byref type. This is not permitted by the rules of Common IL."
FSharpErrorSeverity.Error, 412, (19, 17, 19, 29), "A type instantiation involves a byref type. This is not permitted by the rules of Common IL."
FSharpErrorSeverity.Error, 412, (19, 27, 19, 29), "A type instantiation involves a byref type. This is not permitted by the rules of Common IL."
|]

[<Test>]
let ``Type abbreviation that boxes a span should fail to compile``() =
CompilerAssert.TypeCheckWithErrors """
open System
type TA = Span<int> * Span<int>
let f (x: TA) = ()
"""
[|
FSharpErrorSeverity.Error, 3300, (6, 8, 6, 9), "The parameter 'x' has an invalid type 'TA'. This is not permitted by the rules of Common IL."
|]
#endif
6 changes: 6 additions & 0 deletions tests/fsharp/typecheck/sigs/neg_byref_13.bsl
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@

neg_byref_13.fs(2,6,2,8): typecheck error FS0445: The type abbreviation contains byrefs. This is not permitted by F#.

neg_byref_13.fs(3,12,3,13): typecheck error FS3300: The parameter 'x' has an invalid type 'M5'. This is not permitted by the rules of Common IL.

neg_byref_13.fs(3,5,3,10): typecheck error FS3301: The function or method has an invalid return type 'M5'. This is not permitted by the rules of Common IL.

neg_byref_13.fs(3,20,3,21): typecheck error FS0412: A type instantiation involves a byref type. This is not permitted by the rules of Common IL.

0 comments on commit efccc97

Please sign in to comment.