diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fs b/src/Compiler/SyntaxTree/ParseHelpers.fs index 0440d019fa..f3e3fcdfda 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fs +++ b/src/Compiler/SyntaxTree/ParseHelpers.fs @@ -847,7 +847,7 @@ let adjustHatPrefixToTyparLookup mFull rightExpr = take rightExpr // The last element of elementTypes does not have a star or slash -let mkSynTypeTuple (isStruct: bool) (elementTypes: SynTupleTypeSegment list) : SynType = +let mkSynTypeTuple (elementTypes: SynTupleTypeSegment list) : SynType = let range = match elementTypes with | [] -> Range.Zero @@ -856,4 +856,4 @@ let mkSynTypeTuple (isStruct: bool) (elementTypes: SynTupleTypeSegment list) : S (head.Range, tail) ||> List.fold (fun acc segment -> unionRanges acc segment.Range) - SynType.Tuple(isStruct, elementTypes, range) + SynType.Tuple(false, elementTypes, range) diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fsi b/src/Compiler/SyntaxTree/ParseHelpers.fsi index 1b321cd930..e345dc68a3 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fsi +++ b/src/Compiler/SyntaxTree/ParseHelpers.fsi @@ -179,4 +179,4 @@ val mkSynMemberDefnGetSet: /// Incorporate a '^' for an qualified access to a generic type parameter val adjustHatPrefixToTyparLookup: mFull: range -> rightExpr: SynExpr -> SynExpr -val mkSynTypeTuple: isStruct: bool -> elementTypes: SynTupleTypeSegment list -> SynType +val mkSynTypeTuple: elementTypes: SynTupleTypeSegment list -> SynType diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 065172f640..c0453c0c80 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -5064,7 +5064,7 @@ topTupleType: let mStar = rhs parseState 2 let path = SynTupleTypeSegment.Type t :: SynTupleTypeSegment.Star mStar :: (List.map fst $3) let mdata = argInfo :: (List.choose snd $3) - mkSynTypeTuple false path, mdata } + mkSynTypeTuple path, mdata } | topAppType { let ty, mdata = $1 in ty, [mdata] } @@ -5120,19 +5120,19 @@ tupleType: | appType STAR tupleOrQuotTypeElements { let mStar = rhs parseState 2 let path = SynTupleTypeSegment.Type $1 :: SynTupleTypeSegment.Star mStar :: $3 - mkSynTypeTuple false path } + mkSynTypeTuple path } | INFIX_STAR_DIV_MOD_OP tupleOrQuotTypeElements { if $1 <> "/" then reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnexpectedInfixOperator()); let mSlash = rhs parseState 1 let path = SynTupleTypeSegment.Slash mSlash :: $2 - mkSynTypeTuple false path } + mkSynTypeTuple path } | appType INFIX_STAR_DIV_MOD_OP tupleOrQuotTypeElements { if $2 <> "/" then reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnexpectedInfixOperator()); let mSlash = rhs parseState 2 let path = SynTupleTypeSegment.Type $1 :: SynTupleTypeSegment.Slash mSlash :: $3 - mkSynTypeTuple false path } + mkSynTypeTuple path } | appType %prec prec_tuptyp_prefix { $1 } @@ -5284,13 +5284,15 @@ atomType: | STRUCT LPAREN appType STAR tupleOrQuotTypeElements rparen { let mStar = rhs parseState 4 let path = SynTupleTypeSegment.Type $3 :: SynTupleTypeSegment.Star mStar :: $5 - mkSynTypeTuple true path } + let m = rhs2 parseState 1 6 + SynType.Tuple(true, path, m) } | STRUCT LPAREN appType STAR tupleOrQuotTypeElements recover { reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnmatchedParen()) let mStar = rhs parseState 4 let path = SynTupleTypeSegment.Type $3 :: SynTupleTypeSegment.Star mStar :: $5 - mkSynTypeTuple true path } + let m = rhs2 parseState 1 5 + SynType.Tuple(true, path, m) } | STRUCT LPAREN appType STAR recover { reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnmatchedParen()) diff --git a/tests/service/SyntaxTreeTests/TypeTests.fs b/tests/service/SyntaxTreeTests/TypeTests.fs index b965d7e929..c38e684ada 100644 --- a/tests/service/SyntaxTreeTests/TypeTests.fs +++ b/tests/service/SyntaxTreeTests/TypeTests.fs @@ -484,3 +484,43 @@ let ``SynType.Fun has range of arrow`` () = ])) -> assertRange (2, 21) (2, 23) mArrow | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +[] +let ``SynType.Tuple with struct`` () = + let parseResults = + getParseResults + """ +let _: struct (int * int) = () +""" + + match parseResults with + | ParsedInput.ImplFile (ParsedImplFileInput(modules = [ + SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Let(bindings = [ SynBinding(returnInfo = Some (SynBindingReturnInfo(typeName = + SynType.Tuple(true, [ SynTupleTypeSegment.Type _ ; SynTupleTypeSegment.Star _ ; SynTupleTypeSegment.Type _ ], mTuple)))) ]) + ]) + ]) + ) -> + assertRange (2, 7) (2, 25) mTuple + + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +[] +let ``SynType.Tuple with struct, recovery`` () = + let parseResults = + getParseResults + """ +let _: struct (int * int = () +""" + + match parseResults with + | ParsedInput.ImplFile (ParsedImplFileInput(modules = [ + SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Let(bindings = [ SynBinding(returnInfo = Some (SynBindingReturnInfo(typeName = + SynType.Tuple(true, [ SynTupleTypeSegment.Type _ ; SynTupleTypeSegment.Star _ ; SynTupleTypeSegment.Type _ ], mTuple)))) ]) + ]) + ]) + ) -> + assertRange (2, 7) (2, 24) mTuple + + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}"