Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -4303,6 +4303,9 @@ and TcTypeOrMeasure kindOpt (cenv: cenv) newOk checkConstraints occ (iwsam: Warn
| SynType.LongIdent synLongId ->
TcLongIdentType kindOpt cenv newOk checkConstraints occ iwsam env tpenv synLongId

| MultiDimensionArrayType (rank, elemTy, m) ->
TcElementType cenv newOk checkConstraints occ env tpenv rank elemTy m

| SynType.App (StripParenTypes (SynType.LongIdent longId), _, args, _, _, postfix, m) ->
TcLongIdentAppType kindOpt cenv newOk checkConstraints occ iwsam env tpenv longId postfix args m

Expand Down
26 changes: 20 additions & 6 deletions src/Compiler/Checking/NicePrint.fs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,11 @@ module internal PrintUtilities =
let isArray = not prefix && isArrayTyconRef denv.g tcref
let demangled =
if isArray then
tcref.DisplayNameCore // no backticks for arrays "int[]"
let numberOfCommas = tcref.CompiledName |> Seq.filter (fun c -> c = ',') |> Seq.length
if numberOfCommas = 0 then
"array"
else
$"array{numberOfCommas + 1}d"
else
let name =
if denv.includeStaticParametersInTypeNames then
Expand All @@ -198,11 +202,7 @@ module internal PrintUtilities =
tagEntityRefName denv tcref demangled
|> mkNav tcref.DefinitionRange

let tyconTextL =
if isArray then
tyconTagged |> rightL
else
tyconTagged |> wordL
let tyconTextL = tyconTagged |> wordL

if denv.shortTypeNames then
tyconTextL
Expand Down Expand Up @@ -873,6 +873,16 @@ module PrintTypes =
| [arg] -> layoutTypeWithInfoAndPrec denv env 2 arg ^^ tcL
| args -> bracketIfL (prec <= 1) (bracketL (layoutTypesWithInfoAndPrec denv env 2 (sepL (tagPunctuation ",")) args) --- tcL)

and layoutTypeForGenericMultidimensionalArrays denv env prec tcref innerT level =
let innerLayout = layoutTypeWithInfoAndPrec denv env prec innerT

let arrayLayout =
tagEntityRefName denv tcref $"array{level}d"
|> mkNav tcref.DefinitionRange
|> wordL

innerLayout ^^ arrayLayout

/// Layout a type, taking precedence into account to insert brackets where needed
and layoutTypeWithInfoAndPrec denv env prec ty =
let g = denv.g
Expand All @@ -893,6 +903,10 @@ module PrintTypes =
// Always prefer 'float' to 'float<1>'
| TType_app (tc, args, _) when tc.IsMeasureableReprTycon && List.forall (isDimensionless g) args ->
layoutTypeWithInfoAndPrec denv env prec (reduceTyconRefMeasureableOrProvided g tc args)

// Special case for nested array<array<'t>> shape
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong, and this rule should be removed. Also there are no tests for jagged arrays - they should be added.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will update next week. Thanks for the review

| TTypeMultiDimensionalArrayAsGeneric (tcref, innerT, level) ->
layoutTypeForGenericMultidimensionalArrays denv env prec tcref innerT level

// Layout a type application
| TType_ucase (UnionCaseRef(tc, _), args)
Expand Down
16 changes: 16 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTreeOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1059,3 +1059,19 @@ let getTypeFromTuplePath (path: SynTupleTypeSegment list) : SynType list =
|> List.choose (function
| SynTupleTypeSegment.Type t -> Some t
| _ -> None)

let (|MultiDimensionArrayType|_|) (t: SynType) =
match t with
| SynType.App (StripParenTypes (SynType.LongIdent (SynLongIdent ([ identifier ], _, _))), _, [ elementType ], _, _, true, m) ->
if System.Text.RegularExpressions.Regex.IsMatch(identifier.idText, "^array\d\d?d$") then
let rank =
identifier.idText
|> Seq.filter System.Char.IsDigit
|> Seq.toArray
|> System.String
|> int

Some(rank, elementType, m)
else
None
| _ -> None
2 changes: 2 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTreeOps.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,5 @@ val normalizeTupleExpr: exprs: SynExpr list -> commas: range list -> SynExpr lis
val desugarGetSetMembers: memberDefns: SynMemberDefns -> SynMemberDefns

val getTypeFromTuplePath: path: SynTupleTypeSegment list -> SynType list

val (|MultiDimensionArrayType|_|): t: SynType -> (int * SynType * range) option
16 changes: 15 additions & 1 deletion src/Compiler/TypedTree/TypedTreeOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -10384,7 +10384,7 @@ let (|EmptyModuleOrNamespaces|_|) (moduleOrNamespaceContents: ModuleOrNamespaceC
| ModuleOrNamespaceContents.TMDefRec _
| ModuleOrNamespaceContents.TMDefs _ -> true
| _ -> false)

let emptyModuleOrNamespaces =
defs
|> List.choose (function
Expand All @@ -10407,3 +10407,17 @@ let (|EmptyModuleOrNamespaces|_|) (moduleOrNamespaceContents: ModuleOrNamespaceC
else
None
| _ -> None

let (|TTypeMultiDimensionalArrayAsGeneric|_|) (t: TType) =
let rec (|Impl|_|) t =
match t with
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code is wrong

  1. once again we're matching directly on TType, we should almost never be doing this
  2. it looks like it is detecting jagged arrays, which is wrong

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will have a look next week

| TType_app(tc, [Impl(outerTc, innerT, currentLevel)], _) when tc.DisplayNameCore = "array" ->
Some (outerTc, innerT, currentLevel + 1)
| TType_app(tc, [arg], _) when tc.DisplayNameCore = "array" ->
Some (tc, arg, 1)
| _ -> None

match t with
| Impl (tc, arg, level) ->
if level > 2 then Some (tc, arg, level) else None
| _ -> None
3 changes: 3 additions & 0 deletions src/Compiler/TypedTree/TypedTreeOps.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -2687,3 +2687,6 @@ type TraitConstraintInfo with
/// This will match anything that does not have any types or bindings.
val (|EmptyModuleOrNamespaces|_|):
moduleOrNamespaceContents: ModuleOrNamespaceContents -> (ModuleOrNamespace list) option

/// Captures an application type with a multi-dimensional array as postfix.
val (|TTypeMultiDimensionalArrayAsGeneric|_|): t: TType -> (TyconRef * TType * int) option
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ module Basic =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
(Error 1, Line 10, Col 3, Line 10, Col 59, "This expression was expected to have type\n 'int[]' \nbut here has type\n 'unit' ")
(Error 1, Line 10, Col 3, Line 10, Col 59, "This expression was expected to have type\n 'int array' \nbut here has type\n 'unit' ")
(Error 267, Line 10, Col 3, Line 10, Col 59, "This is not a valid constant expression or custom attribute value")
(Error 850, Line 10, Col 3, Line 10, Col 59, "This attribute cannot be used in this version of F#")
(Error 850, Line 13, Col 3, Line 13, Col 52, "This attribute cannot be used in this version of F#")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,10 @@ module MethodsAndProperties =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
(Error 1, Line 11, Col 24, Line 11, Col 33, "This expression was expected to have type\n ''a[,]' \nbut here has type\n 'int[]' ")
(Error 1, Line 12, Col 25, Line 12, Col 32, "This expression was expected to have type\n ''a[]' \nbut here has type\n 'int[,]' ")
(Error 1, Line 13, Col 26, Line 13, Col 37, "This expression was expected to have type\n ''a[]' \nbut here has type\n 'int[,,]' ")
(Error 1, Line 14, Col 27, Line 14, Col 38, "This expression was expected to have type\n ''a[]' \nbut here has type\n 'int[,,,]' ")
(Error 1, Line 11, Col 24, Line 11, Col 33, "This expression was expected to have type\n ''a array2d' \nbut here has type\n 'int array' ")
(Error 1, Line 12, Col 25, Line 12, Col 32, "This expression was expected to have type\n ''a array' \nbut here has type\n 'int array2d' ")
(Error 1, Line 13, Col 26, Line 13, Col 37, "This expression was expected to have type\n ''a array' \nbut here has type\n 'int array3d' ")
(Error 1, Line 14, Col 27, Line 14, Col 38, "This expression was expected to have type\n ''a array' \nbut here has type\n 'int array4d' ")
]

// SOURCE=E_IndexerArityMismatch02.fs SCFLAGS="--test:ErrorRanges --flaterrors" # E_IndexerArityMismatch02.fs
Expand All @@ -110,10 +110,10 @@ module MethodsAndProperties =
|> verifyCompile
|> shouldFail
|> withDiagnostics [
(Error 1, Line 11, Col 24, Line 11, Col 35, "This expression was expected to have type\n ''a[,,]' \nbut here has type\n 'int[]' ")
(Error 1, Line 12, Col 25, Line 12, Col 32, "This expression was expected to have type\n ''a[]' \nbut here has type\n 'int[,]' ")
(Error 1, Line 13, Col 27, Line 13, Col 38, "This expression was expected to have type\n ''a[,,]' \nbut here has type\n 'int[,,,]' ")
(Error 1, Line 14, Col 27, Line 14, Col 36, "This expression was expected to have type\n ''a[,]' \nbut here has type\n 'int[,,,]' ")
(Error 1, Line 11, Col 24, Line 11, Col 35, "This expression was expected to have type\n ''a array3d' \nbut here has type\n 'int array' ")
(Error 1, Line 12, Col 25, Line 12, Col 32, "This expression was expected to have type\n ''a array' \nbut here has type\n 'int array2d' ")
(Error 1, Line 13, Col 27, Line 13, Col 38, "This expression was expected to have type\n ''a array3d' \nbut here has type\n 'int array4d' ")
(Error 1, Line 14, Col 27, Line 14, Col 36, "This expression was expected to have type\n ''a array2d' \nbut here has type\n 'int array4d' ")
]

// SOURCE=E_IndexerIndeterminateType01.fs SCFLAGS=--test:ErrorRanges # E_IndexerIndeterminateType01.fs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ module RecordTypes =
|> verifyTypeCheck
|> shouldFail
|> withDiagnostics [
(Error 1, Line 7, Col 17, Line 7, Col 47, "This expression was expected to have type\n 'int[]' \nbut here has type\n 'RecType' ")
(Error 1, Line 7, Col 17, Line 7, Col 47, "This expression was expected to have type\n 'int array' \nbut here has type\n 'RecType' ")
]

// SOURCE=E_RecordsNotNull01.fs # E_RecordsNotNull01.fs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@
<Compile Include="Signatures\TestHelpers.fs" />
<Compile Include="Signatures\ModuleOrNamespaceTests.fs" />
<Compile Include="Signatures\RecordTests.fs" />
<Compile Include="Signatures\ArrayTests.fs" />
</ItemGroup>
<ItemGroup>
<Content Include="resources\**" CopyToOutputDirectory="Never" CopyToPublishDirectory="PreserveNewest" />
Expand Down
51 changes: 51 additions & 0 deletions tests/FSharp.Compiler.ComponentTests/Signatures/ArrayTests.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
module FSharp.Compiler.ComponentTests.Signatures.SignatureTests

open Xunit
open FSharp.Compiler.ComponentTests.Signatures.TestHelpers

[<Theory>]
[<InlineData("let a : int[] = [| 1 |]",
"val a: int array")>]
[<InlineData("let b: int array = [| 2 |]",
"val b: int array")>]
[<InlineData("let c: array<int> = [| 3 |]",
"val c: int array")>]
let ``Value with int array return type`` implementation expectedSignature =
assertSingleSignatureBinding implementation expectedSignature

[<Fact>]
let ``2 dimensional array`` () =
assertSingleSignatureBinding
"let a : int[,] = failwith \"todo\""
"val a: int array2d"

[<Fact>]
let ``3 dimensional array`` () =
assertSingleSignatureBinding
"let a : int[,,] = failwith \"todo\""
"val a: int array3d"

[<Fact>]
let ``4 dimensional array`` () =
assertSingleSignatureBinding
"let a : int[,,,] = failwith \"todo\""
"val a: int array4d"

[<Fact>]
let ``5 till 32 dimensional array`` () =
[ 5 .. 32 ]
|> List.iter (fun idx ->
let arrayType =
[ 1 .. idx ]
|> List.fold (fun acc _ -> $"array<{acc}>") "int"

assertSingleSignatureBinding
$"let a : {arrayType} = failwith \"todo\""
$"val a: int array{idx}d"
)

[<Fact>]
let ``Use array2d syntax in implementation`` () =
assertSingleSignatureBinding
"let y : int array2d = Array2D.init 0 0 (fun _ _ -> 0)"
"val y: int array2d"
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

open System
open FsUnit
open FSharp.Test.Compiler

let prependNewline v = String.Concat("\n", v)

Expand All @@ -11,4 +12,9 @@ let equal x =
| :? String as s -> s.Replace("\r\n", "\n") |> box
| x -> x

equal x
equal x

let assertSingleSignatureBinding implementation signature =
FSharp $"module A\n\n{implementation}"
|> printSignatures
|> should equal $"\nmodule A\n\n{signature}"
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ namespace FSharpTest
exception CustomException of details: string
with
member self.Details with get (): string = self.details
"""
|> compile
|> shouldSucceed
|> ignore

[<Fact>]
let ``Array2 in return type`` () =
FSharp """
module Foo

let y : int array2d = Array2D.init 0 0 (fun _ _ -> 0)
"""
|> compile
|> shouldSucceed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ E_LeftToRightOverloadResolution01.fsx(7,23,7,51): typecheck error FS0041: A uniq
Known type of argument: 'a

Candidates:
- System.Console.WriteLine(buffer: char[]) : unit
- System.Console.WriteLine(format: string, [<System.ParamArray>] arg: obj[]) : unit
- System.Console.WriteLine(buffer: char array) : unit
- System.Console.WriteLine(format: string, [<System.ParamArray>] arg: obj array) : unit
- System.Console.WriteLine(value: bool) : unit
- System.Console.WriteLine(value: char) : unit
- System.Console.WriteLine(value: decimal) : unit
Expand All @@ -23,8 +23,8 @@ E_LeftToRightOverloadResolution01.fsx(9,23,9,51): typecheck error FS0041: A uniq
Known type of argument: 'a

Candidates:
- System.Console.WriteLine(buffer: char[]) : unit
- System.Console.WriteLine(format: string, [<System.ParamArray>] arg: obj[]) : unit
- System.Console.WriteLine(buffer: char array) : unit
- System.Console.WriteLine(format: string, [<System.ParamArray>] arg: obj array) : unit
- System.Console.WriteLine(value: bool) : unit
- System.Console.WriteLine(value: char) : unit
- System.Console.WriteLine(value: decimal) : unit
Expand Down
Loading