diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 11a372bb5c5..36f49053ad8 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -4035,7 +4035,7 @@ module TcDeclarations = let mLetPortion = synExpr.Range let fldId = ident (CompilerGeneratedName id.idText, mLetPortion) let headPat = SynPat.LongIdent (SynLongIdent([fldId], [], [None]), None, Some noInferredTypars, SynArgPats.Pats [], None, mLetPortion) - let retInfo = match tyOpt with None -> None | Some ty -> Some (SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range)) + let retInfo = match tyOpt with None -> None | Some ty -> Some (None, SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range)) let isMutable = match propKind with | SynMemberKind.PropertySet @@ -4077,7 +4077,7 @@ module TcDeclarations = | SynMemberKind.PropertyGetSet -> let getter = let rhsExpr = SynExpr.Ident fldId - let retInfo = match tyOpt with None -> None | Some ty -> Some (SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range)) + let retInfo = match tyOpt with None -> None | Some ty -> Some (None, SynReturnInfo((ty, SynInfo.unnamedRetVal), ty.Range)) let attribs = mkAttributeList attribs mMemberPortion let binding = mkSynBinding (xmlDoc, headPat) (access, false, false, mMemberPortion, DebugPointAtBinding.NoneAtInvisible, retInfo, rhsExpr, rhsExpr.Range, [], attribs, Some memberFlags, SynBindingTrivia.Zero) SynMemberDefn.Member (binding, mMemberPortion) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 9e6524f2627..65515a38a69 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -10246,7 +10246,7 @@ and TcNormalizedBinding declKind (cenv: cenv) env tpenv overallTy safeThisValOpt |> fun (r, v) -> (List.map fst r, List.map snd r, List.map snd v) let retAttribs = match rtyOpt with - | Some (SynBindingReturnInfo(_, _, Attributes retAttrs)) -> + | Some (SynBindingReturnInfo(attributes = Attributes retAttrs)) -> rotRetAttribs @ TcAttrs AttributeTargets.ReturnValue true retAttrs | None -> rotRetAttribs let valSynData = @@ -10894,7 +10894,7 @@ and ApplyTypesFromArgumentPatterns (cenv: cenv, env, optionalArgsOK, ty, m, tpen | [] -> match retInfoOpt with | None -> () - | Some (SynBindingReturnInfo (retInfoTy, m, _)) -> + | Some (SynBindingReturnInfo (typeName = retInfoTy; range = m)) -> let retInfoTy, _ = TcTypeAndRecover cenv NewTyparsOK CheckCxs ItemOccurence.UseInType WarnOnIWSAM.Yes env tpenv retInfoTy UnifyTypes cenv env m ty retInfoTy // Property setters always have "unit" return type diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index 7317df67378..b98bd2248c9 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -647,7 +647,7 @@ module ParsedInput = |> Option.orElseWith (fun () -> walkExpr e) |> Option.orElseWith (fun () -> match returnInfo with - | Some (SynBindingReturnInfo (t, _, _)) -> walkType t + | Some (SynBindingReturnInfo (typeName = t)) -> walkType t | None -> None) and walkInterfaceImpl (SynInterfaceImpl (bindings = bindings)) = List.tryPick walkBinding bindings @@ -1662,7 +1662,9 @@ module ParsedInput = List.iter walkAttribute attrs walkPat pat walkExpr e - returnInfo |> Option.iter (fun (SynBindingReturnInfo (t, _, _)) -> walkType t) + + returnInfo + |> Option.iter (fun (SynBindingReturnInfo (typeName = t)) -> walkType t) and walkInterfaceImpl (SynInterfaceImpl (bindings = bindings)) = List.iter walkBinding bindings diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fs b/src/Compiler/SyntaxTree/ParseHelpers.fs index b97bfe2f7c8..fee75795e33 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fs +++ b/src/Compiler/SyntaxTree/ParseHelpers.fs @@ -422,11 +422,11 @@ let mkSynMemberDefnGetSet (parseState: IParseState) (opt_inline: bool) (mWith: range) - (classDefnMemberGetSetElements: (bool * SynAttributeList list * (SynPat * range) * SynReturnInfo option * range option * SynExpr * range) list) + (classDefnMemberGetSetElements: (bool * SynAttributeList list * (SynPat * range) * (range option * SynReturnInfo) option * range option * SynExpr * range) list) (mAnd: range option) (mWhole: range) (propertyNameBindingPat: SynPat) - (optPropertyType: SynReturnInfo option) + (optPropertyType: (range option * SynReturnInfo) option) (visNoLongerUsed: SynAccess option) flagsBuilderAndLeadingKeyword (attrs: SynAttributeList list) diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fsi b/src/Compiler/SyntaxTree/ParseHelpers.fsi index 1192608dbfb..353d8c973c6 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fsi +++ b/src/Compiler/SyntaxTree/ParseHelpers.fsi @@ -166,11 +166,11 @@ val mkSynMemberDefnGetSet: parseState: IParseState -> opt_inline: bool -> mWith: range -> - classDefnMemberGetSetElements: (bool * SynAttributeList list * (SynPat * range) * SynReturnInfo option * range option * SynExpr * range) list -> + classDefnMemberGetSetElements: (bool * SynAttributeList list * (SynPat * range) * (range option * SynReturnInfo) option * range option * SynExpr * range) list -> mAnd: range option -> mWhole: range -> propertyNameBindingPat: SynPat -> - optPropertyType: SynReturnInfo option -> + optPropertyType: (range option * SynReturnInfo) option -> visNoLongerUsed: SynAccess option -> flagsBuilderAndLeadingKeyword: (SynMemberKind -> SynMemberFlags) * SynLeadingKeyword -> attrs: SynAttributeList list -> diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index bdbf10665d0..540adc029e1 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -1065,7 +1065,8 @@ type SynBinding = member x.RangeOfHeadPattern = let (SynBinding (headPat = headPat)) = x in headPat.Range [] -type SynBindingReturnInfo = SynBindingReturnInfo of typeName: SynType * range: range * attributes: SynAttributes +type SynBindingReturnInfo = + | SynBindingReturnInfo of typeName: SynType * range: range * attributes: SynAttributes * trivia: SynBindingReturnInfoTrivia [] type SynMemberFlags = diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index eeee35985e0..3e05507b340 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -1209,7 +1209,12 @@ type SynBinding = /// Represents the return information in a binding for a 'let' or 'member' declaration [] -type SynBindingReturnInfo = SynBindingReturnInfo of typeName: SynType * range: range * attributes: SynAttributes +type SynBindingReturnInfo = + | SynBindingReturnInfo of + typeName: SynType * + range: range * + attributes: SynAttributes * + trivia: SynBindingReturnInfoTrivia /// Represents the flags for a 'member' declaration [] diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs index 56eb08fee4f..72cfa230342 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs @@ -673,8 +673,8 @@ let mkSynBindingRhs staticOptimizations rhsExpr mRhs retInfo = let rhsExpr, retTyOpt = match retInfo with - | Some (SynReturnInfo ((ty, SynArgInfo (rAttribs, _, _)), tym)) -> - SynExpr.Typed(rhsExpr, ty, rhsExpr.Range), Some(SynBindingReturnInfo(ty, tym, rAttribs)) + | Some (mColon, SynReturnInfo ((ty, SynArgInfo (rAttribs, _, _)), tym)) -> + SynExpr.Typed(rhsExpr, ty, rhsExpr.Range), Some(SynBindingReturnInfo(ty, tym, rAttribs, { ColonRange = mColon })) | None -> rhsExpr, None rhsExpr, retTyOpt @@ -684,7 +684,7 @@ let mkSynBinding (vis, isInline, isMutable, mBind, spBind, retInfo, origRhsExpr, mRhs, staticOptimizations, attrs, memberFlagsOpt, trivia) = let info = - SynInfo.InferSynValData(memberFlagsOpt, Some headPat, retInfo, origRhsExpr) + SynInfo.InferSynValData(memberFlagsOpt, Some headPat, Option.map snd retInfo, origRhsExpr) let rhsExpr, retTyOpt = mkSynBindingRhs staticOptimizations origRhsExpr mRhs retInfo let mBind = unionRangeWithXmlDoc xmlDoc mBind diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi b/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi index 5c9df2c48d7..0d8284d7073 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi @@ -269,7 +269,7 @@ val mkSynBindingRhs: staticOptimizations: (SynStaticOptimizationConstraint list * SynExpr) list -> rhsExpr: SynExpr -> mRhs: range -> - retInfo: SynReturnInfo option -> + retInfo: (range option * SynReturnInfo) option -> SynExpr * SynBindingReturnInfo option val mkSynBinding: @@ -279,7 +279,7 @@ val mkSynBinding: isMutable: bool * mBind: range * spBind: DebugPointAtBinding * - retInfo: SynReturnInfo option * + retInfo: (range option * SynReturnInfo) option * origRhsExpr: SynExpr * mRhs: range * staticOptimizations: (SynStaticOptimizationConstraint list * SynExpr) list * diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fs b/src/Compiler/SyntaxTree/SyntaxTrivia.fs index 5fe77d929a1..8f270d2fd80 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fs +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fs @@ -320,4 +320,8 @@ type SynFieldTrivia = static member Zero: SynFieldTrivia = { LeadingKeyword = None } +[] type SynTypeOrTrivia = { OrKeyword: range } + +[] +type SynBindingReturnInfoTrivia = { ColonRange: range option } diff --git a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi index cae5db553e6..b3275f4b365 100644 --- a/src/Compiler/SyntaxTree/SyntaxTrivia.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTrivia.fsi @@ -428,3 +428,11 @@ type SynTypeOrTrivia = /// The syntax range of the `or` keyword OrKeyword: range } + +/// Represents additional information for SynBindingReturnInfo +[] +type SynBindingReturnInfoTrivia = + { + /// The syntax range of the `:` token + ColonRange: range option + } diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 3114c476616..392192dd2b3 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -2647,7 +2647,7 @@ cPrototype: let binding = mkSynBinding (xmlDoc, bindingPat) - (vis, false, false, mWholeBindLhs, DebugPointAtBinding.NoneAtInvisible, Some rty, rhsExpr, mRhs, [], attrs, None, trivia) + (vis, false, false, mWholeBindLhs, DebugPointAtBinding.NoneAtInvisible, Some (None, rty), rhsExpr, mRhs, [], attrs, None, trivia) [], [binding]) } /* A list of arguments in an 'extern' DllImport function definition */ @@ -4995,9 +4995,10 @@ opt_topReturnTypeWithTypeConstraints: { None } | COLON topTypeWithTypeConstraints - { let ty, arity = $2 + { let mColon = rhs parseState 1 + let ty, arity = $2 let arity = (match arity with SynValInfo([], rmdata)-> rmdata | _ -> SynInfo.unnamedRetVal) - Some (SynReturnInfo((ty, arity), rhs parseState 2)) } + Some (Some mColon, SynReturnInfo((ty, arity), rhs parseState 2)) } topType: | topTupleType RARROW topType 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 66c52c10aed..f4ea65a8572 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -5925,9 +5925,11 @@ FSharp.Compiler.Syntax.SynBindingKind: Int32 Tag FSharp.Compiler.Syntax.SynBindingKind: Int32 get_Tag() FSharp.Compiler.Syntax.SynBindingKind: System.String ToString() FSharp.Compiler.Syntax.SynBindingReturnInfo -FSharp.Compiler.Syntax.SynBindingReturnInfo: FSharp.Compiler.Syntax.SynBindingReturnInfo NewSynBindingReturnInfo(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Text.Range, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList]) +FSharp.Compiler.Syntax.SynBindingReturnInfo: FSharp.Compiler.Syntax.SynBindingReturnInfo NewSynBindingReturnInfo(FSharp.Compiler.Syntax.SynType, FSharp.Compiler.Text.Range, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynAttributeList], FSharp.Compiler.SyntaxTrivia.SynBindingReturnInfoTrivia) FSharp.Compiler.Syntax.SynBindingReturnInfo: FSharp.Compiler.Syntax.SynType get_typeName() FSharp.Compiler.Syntax.SynBindingReturnInfo: FSharp.Compiler.Syntax.SynType typeName +FSharp.Compiler.Syntax.SynBindingReturnInfo: FSharp.Compiler.SyntaxTrivia.SynBindingReturnInfoTrivia get_trivia() +FSharp.Compiler.Syntax.SynBindingReturnInfo: FSharp.Compiler.SyntaxTrivia.SynBindingReturnInfoTrivia trivia FSharp.Compiler.Syntax.SynBindingReturnInfo: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.Syntax.SynBindingReturnInfo: FSharp.Compiler.Text.Range range FSharp.Compiler.Syntax.SynBindingReturnInfo: Int32 Tag @@ -9410,6 +9412,11 @@ FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia: FSharp.Compiler.Text. FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia: FSharp.Compiler.Text.Range get_ParenRange() FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia: System.String ToString() FSharp.Compiler.SyntaxTrivia.SynArgPatsNamePatPairsTrivia: Void .ctor(FSharp.Compiler.Text.Range) +FSharp.Compiler.SyntaxTrivia.SynBindingReturnInfoTrivia +FSharp.Compiler.SyntaxTrivia.SynBindingReturnInfoTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] ColonRange +FSharp.Compiler.SyntaxTrivia.SynBindingReturnInfoTrivia: Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range] get_ColonRange() +FSharp.Compiler.SyntaxTrivia.SynBindingReturnInfoTrivia: System.String ToString() +FSharp.Compiler.SyntaxTrivia.SynBindingReturnInfoTrivia: Void .ctor(Microsoft.FSharp.Core.FSharpOption`1[FSharp.Compiler.Text.Range]) FSharp.Compiler.SyntaxTrivia.SynBindingTrivia FSharp.Compiler.SyntaxTrivia.SynBindingTrivia: FSharp.Compiler.SyntaxTrivia.SynBindingTrivia Zero FSharp.Compiler.SyntaxTrivia.SynBindingTrivia: FSharp.Compiler.SyntaxTrivia.SynBindingTrivia get_Zero() @@ -9826,13 +9833,8 @@ FSharp.Compiler.SyntaxTrivia.SynTypeFunTrivia: FSharp.Compiler.Text.Range get_Ar FSharp.Compiler.SyntaxTrivia.SynTypeFunTrivia: System.String ToString() FSharp.Compiler.SyntaxTrivia.SynTypeFunTrivia: Void .ctor(FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia -FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia: Boolean Equals(FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia) -FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia: Boolean Equals(System.Object) -FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia: Boolean Equals(System.Object, System.Collections.IEqualityComparer) FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia: FSharp.Compiler.Text.Range OrKeyword FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia: FSharp.Compiler.Text.Range get_OrKeyword() -FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia: Int32 GetHashCode() -FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia: Int32 GetHashCode(System.Collections.IEqualityComparer) FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia: System.String ToString() FSharp.Compiler.SyntaxTrivia.SynTypeOrTrivia: Void .ctor(FSharp.Compiler.Text.Range) FSharp.Compiler.SyntaxTrivia.SynUnionCaseTrivia diff --git a/tests/service/SyntaxTreeTests/BindingTests.fs b/tests/service/SyntaxTreeTests/BindingTests.fs index 5a05af975e2..e2afdfd7f93 100644 --- a/tests/service/SyntaxTreeTests/BindingTests.fs +++ b/tests/service/SyntaxTreeTests/BindingTests.fs @@ -399,3 +399,43 @@ let b : int * string * bool = 1, "", false ]) ])) -> Assert.Pass () | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +[] +let ``Colon before return type is part of trivia`` () = + let parseResults = + getParseResults """ +let x y : int = failwith "todo" +""" + + match parseResults with + | ParsedInput.ImplFile (ParsedImplFileInput (contents = [ SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Let(bindings = [ + SynBinding(returnInfo = + Some (SynBindingReturnInfo(trivia = { ColonRange = Some mColon }))) + ]) + ]) ])) -> + assertRange (2,8) (2,9) mColon + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +[] +let ``Colon before return type is part of trivia in properties`` () = + let parseResults = + getParseResults """ +type X = + member this.Y with get():int = 1 and set (_:int):unit = () +""" + + match parseResults with + | ParsedInput.ImplFile (ParsedImplFileInput (contents = [ SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Types(typeDefns = [ + SynTypeDefn(typeRepr = SynTypeDefnRepr.ObjectModel(members = [ + SynMemberDefn.GetSetMember( + memberDefnForGet = Some(SynBinding(returnInfo = Some (SynBindingReturnInfo(trivia = { ColonRange = Some mColon1 })))) + memberDefnForSet = Some(SynBinding(returnInfo = Some (SynBindingReturnInfo(trivia = { ColonRange = Some mColon2 })))) + ) + ])) + ]) + ]) ])) -> + assertRange (3,28) (3,29) mColon1 + assertRange (3,52) (3,53) mColon2 + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}"