diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 50efadc072e..8b4b99a745e 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -4353,7 +4353,8 @@ and TcTypeOrMeasure kindOpt (cenv: cenv) newOk checkConstraints occ (iwsam: Warn | SynType.App(arg1, _, args, _, _, postfix, m) -> TcTypeMeasureApp kindOpt cenv newOk checkConstraints occ env tpenv arg1 args postfix m - | SynType.Paren(innerType, _) -> + | SynType.Paren(innerType, _) + | SynType.SignatureParameter(usedType = innerType) -> TcTypeOrMeasure kindOpt cenv newOk checkConstraints occ iwsam env tpenv innerType and CheckIWSAM (cenv: cenv) (env: TcEnv) checkConstraints iwsam m tcref = diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index 9a1a53ac658..9a4263d4975 100755 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -823,8 +823,13 @@ module SyntaxTraversal = | SynType.MeasureDivide (ty1, ty2, _) -> [ ty1; ty2 ] |> List.tryPick (traverseSynType path) | SynType.Tuple (path = segments) -> getTypeFromTuplePath segments |> List.tryPick (traverseSynType path) | SynType.StaticConstantExpr (expr, _) -> traverseSynExpr [] expr - | SynType.Anon _ -> None - | _ -> None + | SynType.Paren (innerType = t) + | SynType.SignatureParameter (usedType = t) -> traverseSynType path t + | SynType.Anon _ + | SynType.AnonRecd _ + | SynType.LongIdent _ + | SynType.Var _ + | SynType.StaticConstant _ -> None visitor.VisitType(origPath, defaultTraverse, ty) diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index d41cef4a04b..7b1fc766c1d 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -669,8 +669,15 @@ module ParsedInput = | SynType.HashConstraint (t, _) -> walkType t | SynType.MeasureDivide (t1, t2, _) -> walkType t1 |> Option.orElseWith (fun () -> walkType t2) | SynType.MeasurePower (t, _, _) -> walkType t - | SynType.Paren (t, _) -> walkType t - | _ -> None + | SynType.Paren (t, _) + | SynType.SignatureParameter (usedType = t) -> walkType t + | SynType.StaticConstantExpr (e, _) -> walkExpr e + | SynType.StaticConstantNamed (ident, value, _) -> List.tryPick walkType [ ident; value ] + | SynType.Anon _ + | SynType.AnonRecd _ + | SynType.LongIdent _ + | SynType.Var _ + | SynType.StaticConstant _ -> None and walkClause clause = let (SynMatchClause (pat = pat; whenExpr = e1; resultExpr = e2)) = clause @@ -1661,7 +1668,8 @@ module ParsedInput = | SynType.Array (_, t, _) | SynType.HashConstraint (t, _) | SynType.MeasurePower (t, _, _) - | SynType.Paren (t, _) -> walkType t + | SynType.Paren (t, _) + | SynType.SignatureParameter (usedType = t) -> walkType t | SynType.Fun (argType = t1; returnType = t2) | SynType.MeasureDivide (t1, t2, _) -> walkType t1 @@ -1675,7 +1683,14 @@ module ParsedInput = | SynType.WithGlobalConstraints (t, typeConstraints, _) -> walkType t List.iter walkTypeConstraint typeConstraints - | _ -> () + | SynType.StaticConstantExpr (e, _) -> walkExpr e + | SynType.StaticConstantNamed (ident, value, _) -> + walkType ident + walkType value + | SynType.Anon _ + | SynType.AnonRecd _ + | SynType.Var _ + | SynType.StaticConstant _ -> () and walkClause (SynMatchClause (pat = pat; whenExpr = e1; resultExpr = e2)) = walkPat pat diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index 8a0b853f63e..ce5571ab4d9 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -435,6 +435,8 @@ type SynType = | Paren of innerType: SynType * range: range + | SignatureParameter of attributes: SynAttributes * optional: bool * id: Ident option * usedType: SynType * range: range + member x.Range = match x with | SynType.App (range = m) @@ -452,7 +454,8 @@ type SynType = | SynType.HashConstraint (range = m) | SynType.MeasureDivide (range = m) | SynType.MeasurePower (range = m) - | SynType.Paren (range = m) -> m + | SynType.Paren (range = m) + | SynType.SignatureParameter (range = m) -> m | SynType.LongIdent lidwd -> lidwd.Range [] diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index 503a7b2faa7..2af399af0e4 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -510,6 +510,14 @@ type SynType = | Paren of innerType: SynType * range: range + /// F# syntax: a: b, used in signatures and type annotations + | SignatureParameter of + attributes: SynAttributes * + optional: bool * + id: Ident option * + usedType: SynType * + range: range + /// Gets the syntax range of this construct member Range: range diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index c0453c0c80c..d7bbdaaf68e 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -5082,22 +5082,29 @@ topTupleTypeElements: topAppType: | attributes appType COLON appType { match $2 with - | SynType.LongIdent(SynLongIdent([id], _, _)) -> $4, SynArgInfo($1, false, Some id) + | SynType.LongIdent(SynLongIdent([id], _, _)) -> + let m = rhs2 parseState 1 4 + SynType.SignatureParameter($1, false, Some id, $4, m), SynArgInfo($1, false, Some id) | _ -> raiseParseErrorAt (rhs parseState 2) (FSComp.SR.parsSyntaxErrorInLabeledType()) } | attributes QMARK ident COLON appType - { $5, SynArgInfo($1, true, Some $3) } + { let m = rhs2 parseState 1 5 + SynType.SignatureParameter($1, true, Some $3, $5, m), SynArgInfo($1, true, Some $3) } | attributes appType - { ($2, SynArgInfo($1, false, None)) } + { let m = rhs2 parseState 1 2 + SynType.SignatureParameter($1, false, None, $2, m), SynArgInfo($1, false, None) } | appType COLON appType { match $1 with - | SynType.LongIdent(SynLongIdent([id], _, _)) -> $3, SynArgInfo([], false, Some id) + | SynType.LongIdent(SynLongIdent([id], _, _)) -> + let m = rhs2 parseState 1 3 + SynType.SignatureParameter([], false, Some id, $3, m), SynArgInfo([], false, Some id) | _ -> raiseParseErrorAt (rhs parseState 2) (FSComp.SR.parsSyntaxErrorInLabeledType()) } | QMARK ident COLON appType - { $4, SynArgInfo([], true, Some $2) } + { let m = rhs2 parseState 1 4 + SynType.SignatureParameter([], true, Some $2, $4, m), SynArgInfo([], true, Some $2) } | appType { $1, SynArgInfo([], false, None) } diff --git a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected index b808314ad58..083c2ea9310 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -8483,6 +8483,16 @@ FSharp.Compiler.Syntax.SynType+Paren: FSharp.Compiler.Syntax.SynType get_innerTy FSharp.Compiler.Syntax.SynType+Paren: FSharp.Compiler.Syntax.SynType innerType FSharp.Compiler.Syntax.SynType+Paren: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.Syntax.SynType+Paren: FSharp.Compiler.Text.Range range +FSharp.Compiler.Syntax.SynType+SignatureParameter: Boolean get_optional() +FSharp.Compiler.Syntax.SynType+SignatureParameter: Boolean optional +FSharp.Compiler.Syntax.SynType+SignatureParameter: FSharp.Compiler.Syntax.SynType get_usedType() +FSharp.Compiler.Syntax.SynType+SignatureParameter: FSharp.Compiler.Syntax.SynType usedType +FSharp.Compiler.Syntax.SynType+SignatureParameter: FSharp.Compiler.Text.Range get_range() +FSharp.Compiler.Syntax.SynType+SignatureParameter: FSharp.Compiler.Text.Range range +FSharp.Compiler.Syntax.SynType+SignatureParameter: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList] attributes +FSharp.Compiler.Syntax.SynType+SignatureParameter: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList] get_attributes() +FSharp.Compiler.Syntax.SynType+SignatureParameter: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident] get_id() +FSharp.Compiler.Syntax.SynType+SignatureParameter: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident] id FSharp.Compiler.Syntax.SynType+StaticConstant: FSharp.Compiler.Syntax.SynConst constant FSharp.Compiler.Syntax.SynType+StaticConstant: FSharp.Compiler.Syntax.SynConst get_constant() FSharp.Compiler.Syntax.SynType+StaticConstant: FSharp.Compiler.Text.Range get_range() @@ -8508,6 +8518,7 @@ FSharp.Compiler.Syntax.SynType+Tags: Int32 LongIdentApp FSharp.Compiler.Syntax.SynType+Tags: Int32 MeasureDivide FSharp.Compiler.Syntax.SynType+Tags: Int32 MeasurePower FSharp.Compiler.Syntax.SynType+Tags: Int32 Paren +FSharp.Compiler.Syntax.SynType+Tags: Int32 SignatureParameter FSharp.Compiler.Syntax.SynType+Tags: Int32 StaticConstant FSharp.Compiler.Syntax.SynType+Tags: Int32 StaticConstantExpr FSharp.Compiler.Syntax.SynType+Tags: Int32 StaticConstantNamed @@ -8541,6 +8552,7 @@ FSharp.Compiler.Syntax.SynType: Boolean IsLongIdentApp FSharp.Compiler.Syntax.SynType: Boolean IsMeasureDivide FSharp.Compiler.Syntax.SynType: Boolean IsMeasurePower FSharp.Compiler.Syntax.SynType: Boolean IsParen +FSharp.Compiler.Syntax.SynType: Boolean IsSignatureParameter FSharp.Compiler.Syntax.SynType: Boolean IsStaticConstant FSharp.Compiler.Syntax.SynType: Boolean IsStaticConstantExpr FSharp.Compiler.Syntax.SynType: Boolean IsStaticConstantNamed @@ -8558,6 +8570,7 @@ FSharp.Compiler.Syntax.SynType: Boolean get_IsLongIdentApp() FSharp.Compiler.Syntax.SynType: Boolean get_IsMeasureDivide() FSharp.Compiler.Syntax.SynType: Boolean get_IsMeasurePower() FSharp.Compiler.Syntax.SynType: Boolean get_IsParen() +FSharp.Compiler.Syntax.SynType: Boolean get_IsSignatureParameter() FSharp.Compiler.Syntax.SynType: Boolean get_IsStaticConstant() FSharp.Compiler.Syntax.SynType: Boolean get_IsStaticConstantExpr() FSharp.Compiler.Syntax.SynType: Boolean get_IsStaticConstantNamed() @@ -8575,6 +8588,7 @@ FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewLongIdentApp(F FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewMeasureDivide(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewMeasurePower(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynRationalConst, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewParen(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewSignatureParameter(Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList], Boolean, Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Syntax.Ident], FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewStaticConstant(FSharp.Compiler.Syntax.SynConst, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewStaticConstantExpr(FSharp.Compiler.Syntax.SynExpr, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewStaticConstantNamed(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Text.Range) @@ -8592,6 +8606,7 @@ FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType+LongIdentApp FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType+MeasureDivide FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType+MeasurePower FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType+Paren +FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType+SignatureParameter FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType+StaticConstant FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType+StaticConstantExpr FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType+StaticConstantNamed diff --git a/tests/service/SyntaxTreeTests/SignatureTypeTests.fs b/tests/service/SyntaxTreeTests/SignatureTypeTests.fs index 943fa5ba5e3..e7f8055fee9 100644 --- a/tests/service/SyntaxTreeTests/SignatureTypeTests.fs +++ b/tests/service/SyntaxTreeTests/SignatureTypeTests.fs @@ -471,3 +471,44 @@ type Z with assertRange (14, 0) (14, 4) mType3 assertRange (14, 7) (14, 11) mWith3 | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +[] +let ``SynValSig contains parameter names`` () = + let parseResults = + getParseResultsOfSignatureFile + """ +module Meh +val InferSynValData: + memberFlagsOpt: SynMemberFlags option * pat: SynPat option * SynReturnInfo option * origRhsExpr: SynExpr -> + x: string -> + SynValData2 +""" + + match parseResults with + | ParsedInput.SigFile (ParsedSigFileInput (modules=[ + SynModuleOrNamespaceSig(decls=[ + SynModuleSigDecl.Val(valSig = SynValSig(synType = + SynType.Fun( + argType = + SynType.Tuple(path = [ + SynTupleTypeSegment.Type(SynType.SignatureParameter(id = Some memberFlagsOpt)) + SynTupleTypeSegment.Star _ + SynTupleTypeSegment.Type(SynType.SignatureParameter(id = Some pat)) + SynTupleTypeSegment.Star _ + SynTupleTypeSegment.Type(SynType.App _) + SynTupleTypeSegment.Star _ + SynTupleTypeSegment.Type(SynType.SignatureParameter(id = Some origRhsExpr)) + ]) + returnType = + SynType.Fun( + argType = SynType.SignatureParameter(id = Some x) + returnType = SynType.LongIdent _ + ) + ) + )) + ] ) ])) -> + Assert.AreEqual("memberFlagsOpt", memberFlagsOpt.idText) + Assert.AreEqual("pat", pat.idText) + Assert.AreEqual("origRhsExpr", origRhsExpr.idText) + Assert.AreEqual("x", x.idText) + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" \ No newline at end of file diff --git a/tests/service/SyntaxTreeTests/TypeTests.fs b/tests/service/SyntaxTreeTests/TypeTests.fs index c38e684ada3..0c822ea94dc 100644 --- a/tests/service/SyntaxTreeTests/TypeTests.fs +++ b/tests/service/SyntaxTreeTests/TypeTests.fs @@ -524,3 +524,73 @@ let _: struct (int * int = () assertRange (2, 7) (2, 24) mTuple | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +[] +let ``Named parameters in delegate type`` () = + let parseResults = + getParseResults + """ +type Foo = delegate of a: A * b: B -> c:C -> D + """ + + match parseResults with + | ParsedInput.ImplFile (ParsedImplFileInput(modules = [ + SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Types(typeDefns = [ + SynTypeDefn(typeRepr = SynTypeDefnRepr.ObjectModel(kind = + SynTypeDefnKind.Delegate(signature = SynType.Fun( + argType = + SynType.Tuple(path = [ + SynTupleTypeSegment.Type(SynType.SignatureParameter(id = Some a)) + SynTupleTypeSegment.Star _ + SynTupleTypeSegment.Type(SynType.SignatureParameter(id = Some b)) + ]) + returnType = + SynType.Fun( + argType = SynType.SignatureParameter(id = Some c) + returnType = SynType.LongIdent _ + ) + )))) + ]) + ]) + ])) -> + Assert.AreEqual("a", a.idText) + Assert.AreEqual("b", b.idText) + Assert.AreEqual("c", c.idText) + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +[] +let ``Attributes in optional named member parameter`` () = + let parseResults = + getParseResults + """ +type X = + abstract member Y: [] ?a: A -> B + """ + + match parseResults with + | ParsedInput.ImplFile (ParsedImplFileInput(modules = [ + SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Types(typeDefns = [ + SynTypeDefn(typeRepr = SynTypeDefnRepr.ObjectModel( + members = [ + SynMemberDefn.AbstractSlot(slotSig = SynValSig(synType = + SynType.Fun( + argType = SynType.SignatureParameter( + [ { Attributes = [ _ ; _ ] } ], + true, + Some a, + SynType.LongIdent _, + m + ) + returnType = SynType.LongIdent _ + ) + )) + ] + )) + ]) + ]) + ])) -> + Assert.AreEqual("a", a.idText) + assertRange (3, 23) (3, 41) m + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" \ No newline at end of file diff --git a/tests/service/SyntaxTreeTests/UnionCaseTests.fs b/tests/service/SyntaxTreeTests/UnionCaseTests.fs index 2cb1f80b730..c9c480cc16e 100644 --- a/tests/service/SyntaxTreeTests/UnionCaseTests.fs +++ b/tests/service/SyntaxTreeTests/UnionCaseTests.fs @@ -135,4 +135,31 @@ type Currency = ])) -> assertRange (7, 4) (7, 11) mPrivate | _ -> - Assert.Fail "Could not get valid AST" \ No newline at end of file + Assert.Fail "Could not get valid AST" + +[] +let ``SynUnionCaseKind.FullType`` () = + let parseResults = + getParseResults + """ +type X = + | a: int * z:int + """ + + match parseResults with + | ParsedInput.ImplFile (ParsedImplFileInput(modules = [ + SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Types(typeDefns = [ + SynTypeDefn(typeRepr = SynTypeDefnRepr.Simple(simpleRepr = + SynTypeDefnSimpleRepr.Union(unionCases = [ + SynUnionCase(caseType = SynUnionCaseKind.FullType(fullType = SynType.Tuple(path = [ + SynTupleTypeSegment.Type(SynType.LongIdent _) + SynTupleTypeSegment.Star _ + SynTupleTypeSegment.Type(SynType.SignatureParameter(id = Some z)) + ]))) + ]))) + ]) + ]) + ])) -> + Assert.AreEqual("z", z.idText) + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" \ No newline at end of file