diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 7e3baef258b..fd970a58cac 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -4538,8 +4538,8 @@ and TcTypeOrMeasure kindOpt cenv newOk checkConstraints occ env (tpenv: Unscoped | SynType.LongIdentApp (synLeftTy, synLongId, _, args, _commas, _, m) -> TcNestedAppType cenv newOk checkConstraints occ env tpenv synLeftTy synLongId args m - | SynType.Tuple(isStruct, args, m) -> - TcTupleType kindOpt cenv newOk checkConstraints occ env tpenv isStruct args m + | SynType.Tuple(isStruct, segments, m) -> + TcTupleType kindOpt cenv newOk checkConstraints occ env tpenv isStruct segments m | SynType.AnonRecd(_, [],m) -> error(Error((FSComp.SR.tcAnonymousTypeInvalidInDeclaration()), m)) @@ -4649,8 +4649,7 @@ and TcNestedAppType cenv newOk checkConstraints occ env tpenv synLeftTy synLongI | _ -> error(Error(FSComp.SR.tcTypeHasNoNestedTypes(), m)) -and TcTupleType kindOpt cenv newOk checkConstraints occ env tpenv isStruct args m = - +and TcTupleType kindOpt cenv newOk checkConstraints occ env tpenv isStruct (args: SynTupleTypeSegment list) m = let tupInfo = mkTupInfo isStruct if isStruct then let argsR,tpenv = TcTypesAsTuple cenv newOk checkConstraints occ env tpenv args m @@ -4659,8 +4658,9 @@ and TcTupleType kindOpt cenv newOk checkConstraints occ env tpenv isStruct args let isMeasure = match kindOpt with | Some TyparKind.Measure -> true - | None -> List.exists (fun (isquot,_) -> isquot) args | _ -> false - + | None -> args |> List.exists(function | SynTupleTypeSegment.Slash _ -> true | _ -> false) + | Some _ -> false + if isMeasure then let ms,tpenv = TcMeasuresAsTuple cenv newOk checkConstraints occ env tpenv args m TType_measure ms,tpenv @@ -4670,7 +4670,7 @@ and TcTupleType kindOpt cenv newOk checkConstraints occ env tpenv isStruct args and TcAnonRecdType cenv newOk checkConstraints occ env tpenv isStruct args m = let tupInfo = mkTupInfo isStruct - let tup = args |> List.map snd |> List.map (fun x -> (false, x)) + let tup = args |> List.map (fun (_, t) -> SynTupleTypeSegment.Type t) let argsR,tpenv = TcTypesAsTuple cenv newOk checkConstraints occ env tpenv tup m let unsortedFieldIds = args |> List.map fst |> List.toArray let anonInfo = AnonRecdTypeInfo.Create(cenv.thisCcu, tupInfo, unsortedFieldIds) @@ -4808,25 +4808,39 @@ and TcAnonTypeOrMeasure kindOpt _cenv rigid dyn newOk m = and TcTypes cenv newOk checkConstraints occ env tpenv args = List.mapFold (TcTypeAndRecover cenv newOk checkConstraints occ env) tpenv args -and TcTypesAsTuple cenv newOk checkConstraints occ env tpenv args m = +and TcTypesAsTuple cenv newOk checkConstraints occ env tpenv (args: SynTupleTypeSegment list) m = + let hasASlash = + args + |> List.exists(function | SynTupleTypeSegment.Slash _ -> true | _ -> false) + + if hasASlash then errorR(Error(FSComp.SR.tcUnexpectedSlashInType(), m)) + + let args : SynType list = getTypeFromTuplePath args match args with | [] -> error(InternalError("empty tuple type", m)) - | [(_, ty)] -> let ty, tpenv = TcTypeAndRecover cenv newOk checkConstraints occ env tpenv ty in [ty], tpenv - | (isquot, ty) :: args -> + | [ty] -> let ty, tpenv = TcTypeAndRecover cenv newOk checkConstraints occ env tpenv ty in [ty], tpenv + | ty :: args -> let ty, tpenv = TcTypeAndRecover cenv newOk checkConstraints occ env tpenv ty + let args = List.map SynTupleTypeSegment.Type args let tys, tpenv = TcTypesAsTuple cenv newOk checkConstraints occ env tpenv args m - if isquot then errorR(Error(FSComp.SR.tcUnexpectedSlashInType(), m)) ty :: tys, tpenv // Type-check a list of measures separated by juxtaposition, * or / -and TcMeasuresAsTuple cenv newOk checkConstraints occ env (tpenv: UnscopedTyparEnv) args m = - let rec gather args tpenv isquot acc = +and TcMeasuresAsTuple cenv newOk checkConstraints occ env (tpenv: UnscopedTyparEnv) (args: SynTupleTypeSegment list) m = + let rec gather (args: SynTupleTypeSegment list) tpenv acc = match args with | [] -> acc, tpenv - | (nextisquot, ty) :: args -> + | SynTupleTypeSegment.Type ty :: args -> + let ms1, tpenv = TcMeasure cenv newOk checkConstraints occ env tpenv ty m + gather args tpenv ms1 + | SynTupleTypeSegment.Star _ :: SynTupleTypeSegment.Type ty :: args -> + let ms1, tpenv = TcMeasure cenv newOk checkConstraints occ env tpenv ty m + gather args tpenv (Measure.Prod(acc, ms1)) + | SynTupleTypeSegment.Slash _ :: SynTupleTypeSegment.Type ty :: args -> let ms1, tpenv = TcMeasure cenv newOk checkConstraints occ env tpenv ty m - gather args tpenv nextisquot (if isquot then Measure.Prod(acc, Measure.Inv ms1) else Measure.Prod(acc, ms1)) - gather args tpenv false Measure.One + gather args tpenv (Measure.Prod(acc, Measure.Inv ms1)) + | _ -> failwith "inpossible" + gather args tpenv Measure.One and TcTypesOrMeasures optKinds cenv newOk checkConstraints occ env tpenv args m = match optKinds with diff --git a/src/Compiler/Service/ServiceParseTreeWalk.fs b/src/Compiler/Service/ServiceParseTreeWalk.fs index e2eedc9ba47..6e4812eeb6d 100755 --- a/src/Compiler/Service/ServiceParseTreeWalk.fs +++ b/src/Compiler/Service/ServiceParseTreeWalk.fs @@ -819,7 +819,7 @@ module SyntaxTraversal = | SynType.Array (_, ty, _) -> traverseSynType path ty | SynType.StaticConstantNamed (ty1, ty2, _) | SynType.MeasureDivide (ty1, ty2, _) -> [ ty1; ty2 ] |> List.tryPick (traverseSynType path) - | SynType.Tuple (_, tys, _) -> tys |> List.map snd |> List.tryPick (traverseSynType path) + | SynType.Tuple (path = segments) -> getTypeFromTuplePath segments |> List.tryPick (traverseSynType path) | SynType.StaticConstantExpr (expr, _) -> traverseSynExpr [] expr | SynType.Anon _ -> None | _ -> None diff --git a/src/Compiler/Service/ServiceParsedInputOps.fs b/src/Compiler/Service/ServiceParsedInputOps.fs index a7ffb760e5a..662a420ae0b 100644 --- a/src/Compiler/Service/ServiceParsedInputOps.fs +++ b/src/Compiler/Service/ServiceParsedInputOps.fs @@ -661,7 +661,7 @@ module ParsedInput = None | SynType.App (ty, _, types, _, _, _, _) -> walkType ty |> Option.orElseWith (fun () -> List.tryPick walkType types) | SynType.LongIdentApp (_, _, _, types, _, _, _) -> List.tryPick walkType types - | SynType.Tuple (_, ts, _) -> ts |> List.tryPick (fun (_, t) -> walkType t) + | SynType.Tuple (path = segments) -> getTypeFromTuplePath segments |> List.tryPick walkType | SynType.Array (_, t, _) -> walkType t | SynType.Fun (argType = t1; returnType = t2) -> walkType t1 |> Option.orElseWith (fun () -> walkType t2) | SynType.WithGlobalConstraints (t, _, _) -> walkType t @@ -1669,7 +1669,7 @@ module ParsedInput = walkType ty List.iter walkType types | SynType.LongIdentApp (_, _, _, types, _, _, _) -> List.iter walkType types - | SynType.Tuple (_, ts, _) -> ts |> List.iter (fun (_, t) -> walkType t) + | SynType.Tuple (path = segment) -> getTypeFromTuplePath segment |> List.iter walkType | SynType.WithGlobalConstraints (t, typeConstraints, _) -> walkType t List.iter walkTypeConstraint typeConstraints diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fs b/src/Compiler/SyntaxTree/ParseHelpers.fs index ff7a44e98a4..4cb172651ad 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fs +++ b/src/Compiler/SyntaxTree/ParseHelpers.fs @@ -811,3 +811,15 @@ let mkSynMemberDefnGetSet [] | _ -> [] | _ -> [] + +// The last element of elementTypes does not have a star or slash +let mkSynTypeTuple (isStruct: bool) (elementTypes: SynTupleTypeSegment list) : SynType = + let range = + match elementTypes with + | [] -> Range.Zero + | head :: tail -> + + (head.Range, tail) + ||> List.fold (fun acc segment -> unionRanges acc segment.Range) + + SynType.Tuple(isStruct, elementTypes, range) diff --git a/src/Compiler/SyntaxTree/ParseHelpers.fsi b/src/Compiler/SyntaxTree/ParseHelpers.fsi index c240ab124e5..e84c3759fbe 100644 --- a/src/Compiler/SyntaxTree/ParseHelpers.fsi +++ b/src/Compiler/SyntaxTree/ParseHelpers.fsi @@ -175,3 +175,5 @@ val mkSynMemberDefnGetSet: attrs: SynAttributeList list -> rangeStart: range -> SynMemberDefn list + +val mkSynTypeTuple: isStruct: bool -> elementTypes: SynTupleTypeSegment list -> SynType diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fs b/src/Compiler/SyntaxTree/SyntaxTree.fs index 500aef1d3ea..cf4e3e1b4da 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fs +++ b/src/Compiler/SyntaxTree/SyntaxTree.fs @@ -369,6 +369,18 @@ type SynTyparDecls = | PrefixList (range = range) -> range | SinglePrefix (range = range) -> range +[] +type SynTupleTypeSegment = + | Type of typeName: SynType + | Star of range: range + | Slash of range: range + + member this.Range = + match this with + | SynTupleTypeSegment.Type t -> t.Range + | SynTupleTypeSegment.Star (range = range) + | SynTupleTypeSegment.Slash (range = range) -> range + [] type SynType = @@ -392,7 +404,7 @@ type SynType = greaterRange: range option * range: range - | Tuple of isStruct: bool * elementTypes: (bool * SynType) list * range: range + | Tuple of isStruct: bool * path: SynTupleTypeSegment list * range: range | AnonRecd of isStruct: bool * fields: (Ident * SynType) list * range: range diff --git a/src/Compiler/SyntaxTree/SyntaxTree.fsi b/src/Compiler/SyntaxTree/SyntaxTree.fsi index 988d7d8cad3..60815a6df09 100644 --- a/src/Compiler/SyntaxTree/SyntaxTree.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTree.fsi @@ -427,6 +427,14 @@ type SynTyparDecls = member Constraints: SynTypeConstraint list member Range: range +[] +type SynTupleTypeSegment = + | Type of typeName: SynType + | Star of range: range + | Slash of range: range + + member Range: range + /// Represents a syntax tree for F# types [] type SynType = @@ -457,11 +465,7 @@ type SynType = /// F# syntax: type * ... * type /// F# syntax: struct (type * ... * type) - | Tuple of - // the bool is true if / rather than * follows the type - isStruct: bool * - elementTypes: (bool * SynType) list * - range: range + | Tuple of isStruct: bool * path: SynTupleTypeSegment list * range: range /// F# syntax: {| id: type; ...; id: type |} /// F# syntax: struct {| id: type; ...; id: type |} diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs index 1834bb0fbf7..24ffaf78a98 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs @@ -1017,3 +1017,9 @@ let rec desugarGetSetMembers (memberDefns: SynMemberDefns) = let members = Option.map desugarGetSetMembers members [ SynMemberDefn.Interface(interfaceType, withKeyword, members, m) ] | md -> [ md ]) + +let getTypeFromTuplePath (path: SynTupleTypeSegment list) : SynType list = + path + |> List.choose (function + | SynTupleTypeSegment.Type t -> Some t + | _ -> None) diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi b/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi index 0c7010b40fa..7af4403fac2 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi @@ -344,3 +344,5 @@ val mkDynamicArgExpr: expr: SynExpr -> SynExpr val normalizeTupleExpr: exprs: SynExpr list -> commas: range list -> SynExpr list * range List val desugarGetSetMembers: memberDefns: SynMemberDefns -> SynMemberDefns + +val getTypeFromTuplePath: path: SynTupleTypeSegment list -> SynType list diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index c7deb4d4fc6..98a75cbeca9 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -5029,17 +5029,23 @@ topType: topTupleType: | topAppType STAR topTupleTypeElements - { let ty, mdata = $1 in let tys, mdatas = List.unzip $3 in (SynType.Tuple(false, List.map (fun ty -> (false, ty)) (ty :: tys), lhs parseState)), (mdata :: mdatas) } + { let t, argInfo = $1 + let path = SynTupleTypeSegment.Type t :: (List.map fst $3) + let mdata = argInfo :: (List.choose snd $3) + mkSynTypeTuple false path, mdata } | topAppType { let ty, mdata = $1 in ty, [mdata] } topTupleTypeElements: | topAppType STAR topTupleTypeElements - { $1 :: $3 } + { let t, argInfo = $1 + let mStar = rhs parseState 2 + (SynTupleTypeSegment.Type t, Some argInfo) :: (SynTupleTypeSegment.Star mStar, None) :: $3 } | topAppType %prec prec_toptuptyptail_prefix - { [$1] } + { let t, argInfo = $1 + [ SynTupleTypeSegment.Type t, Some argInfo ] } topAppType: | attributes appType COLON appType @@ -5080,29 +5086,37 @@ typEOF: tupleType: | appType STAR tupleOrQuotTypeElements - { SynType.Tuple(false, (false, $1) :: $3, lhs parseState) } + { let mStar = rhs parseState 2 + let path = SynTupleTypeSegment.Type $1 :: SynTupleTypeSegment.Star mStar :: $3 + mkSynTypeTuple false path } | INFIX_STAR_DIV_MOD_OP tupleOrQuotTypeElements { if $1 <> "/" then reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnexpectedInfixOperator()); - SynType.Tuple(false, (true, SynType.StaticConstant (SynConst.Int32 1, lhs parseState)) :: $2, lhs parseState) } + let mSlash = rhs parseState 1 + let path = SynTupleTypeSegment.Slash mSlash :: $2 + mkSynTypeTuple false path } | appType INFIX_STAR_DIV_MOD_OP tupleOrQuotTypeElements { if $2 <> "/" then reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnexpectedInfixOperator()); - SynType.Tuple(false, (true, $1) :: $3, lhs parseState) } + let mSlash = rhs parseState 2 + let path = SynTupleTypeSegment.Type $1 :: SynTupleTypeSegment.Slash mSlash :: $3 + mkSynTypeTuple false path } | appType %prec prec_tuptyp_prefix { $1 } tupleOrQuotTypeElements: | appType STAR tupleOrQuotTypeElements - { (false, $1) :: $3 } + { let mStar = rhs parseState 2 + SynTupleTypeSegment.Type $1 :: SynTupleTypeSegment.Star mStar :: $3 } | appType INFIX_STAR_DIV_MOD_OP tupleOrQuotTypeElements { if $2 <> "/" then reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnexpectedInfixOperator()); - (true, $1) :: $3 } + let mSlash = rhs parseState 2 + SynTupleTypeSegment.Type $1 :: SynTupleTypeSegment.Slash mSlash :: $3 } | appType %prec prec_tuptyptail_prefix - { [(false, $1)] } + { [ SynTupleTypeSegment.Type $1 ] } appTypeCon: | path %prec prec_atomtyp_path @@ -5236,11 +5250,15 @@ atomType: SynType.Paren ($2, lhs parseState) } | STRUCT LPAREN appType STAR tupleOrQuotTypeElements rparen - { SynType.Tuple(true, (false, $3) :: $5, lhs parseState) } + { let mStar = rhs parseState 4 + let path = SynTupleTypeSegment.Type $3 :: SynTupleTypeSegment.Star mStar :: $5 + mkSynTypeTuple true path } | STRUCT LPAREN appType STAR tupleOrQuotTypeElements recover { reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnmatchedParen()) - SynType.Tuple(true, (false, $3) :: $5, lhs parseState) } + let mStar = rhs parseState 4 + let path = SynTupleTypeSegment.Type $3 :: SynTupleTypeSegment.Star mStar :: $5 + mkSynTypeTuple true path } | STRUCT LPAREN appType STAR recover { reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnmatchedParen()) 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 1f16bf7c33c..643f6c7ce3e 100644 --- a/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected +++ b/tests/FSharp.Compiler.Service.Tests/FSharp.CompilerService.SurfaceArea.netstandard.expected @@ -2081,12 +2081,14 @@ FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: System.String get_FileName( FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: System.String[] DependencyFiles FSharp.Compiler.CodeAnalysis.FSharpParseFileResults: System.String[] get_DependencyFiles() FSharp.Compiler.CodeAnalysis.FSharpParsingOptions +FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean ApplyLineDirectives FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean CompilingFSharpCore FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean Equals(FSharp.Compiler.CodeAnalysis.FSharpParsingOptions) FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean Equals(System.Object) FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean Equals(System.Object, System.Collections.IEqualityComparer) FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean IsExe FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean IsInteractive +FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean get_ApplyLineDirectives() FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean get_CompilingFSharpCore() FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean get_IsExe() FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean get_IsInteractive() @@ -2108,8 +2110,6 @@ FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: System.String ToString() FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: System.String get_LangVersionText() FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: System.String[] SourceFiles FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: System.String[] get_SourceFiles() -FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean ApplyLineDirectives -FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Boolean get_ApplyLineDirectives() FSharp.Compiler.CodeAnalysis.FSharpParsingOptions: Void .ctor(System.String[], Boolean, Microsoft.FSharp.Collections.FSharpList`1[System.String], FSharp.Compiler.Diagnostics.FSharpDiagnosticOptions, System.String, Boolean, Microsoft.FSharp.Core.FSharpOption`1[System.Boolean], Boolean, Boolean) FSharp.Compiler.CodeAnalysis.FSharpProjectContext FSharp.Compiler.CodeAnalysis.FSharpProjectContext: FSharp.Compiler.CodeAnalysis.FSharpProjectOptions ProjectOptions @@ -8307,6 +8307,34 @@ FSharp.Compiler.Syntax.SynStringKind: Int32 GetHashCode(System.Collections.IEqua FSharp.Compiler.Syntax.SynStringKind: Int32 Tag FSharp.Compiler.Syntax.SynStringKind: Int32 get_Tag() FSharp.Compiler.Syntax.SynStringKind: System.String ToString() +FSharp.Compiler.Syntax.SynTupleTypeSegment +FSharp.Compiler.Syntax.SynTupleTypeSegment+Slash: FSharp.Compiler.Text.Range get_range() +FSharp.Compiler.Syntax.SynTupleTypeSegment+Slash: FSharp.Compiler.Text.Range range +FSharp.Compiler.Syntax.SynTupleTypeSegment+Star: FSharp.Compiler.Text.Range get_range() +FSharp.Compiler.Syntax.SynTupleTypeSegment+Star: FSharp.Compiler.Text.Range range +FSharp.Compiler.Syntax.SynTupleTypeSegment+Tags: Int32 Slash +FSharp.Compiler.Syntax.SynTupleTypeSegment+Tags: Int32 Star +FSharp.Compiler.Syntax.SynTupleTypeSegment+Tags: Int32 Type +FSharp.Compiler.Syntax.SynTupleTypeSegment+Type: FSharp.Compiler.Syntax.SynType get_typeName() +FSharp.Compiler.Syntax.SynTupleTypeSegment+Type: FSharp.Compiler.Syntax.SynType typeName +FSharp.Compiler.Syntax.SynTupleTypeSegment: Boolean IsSlash +FSharp.Compiler.Syntax.SynTupleTypeSegment: Boolean IsStar +FSharp.Compiler.Syntax.SynTupleTypeSegment: Boolean IsType +FSharp.Compiler.Syntax.SynTupleTypeSegment: Boolean get_IsSlash() +FSharp.Compiler.Syntax.SynTupleTypeSegment: Boolean get_IsStar() +FSharp.Compiler.Syntax.SynTupleTypeSegment: Boolean get_IsType() +FSharp.Compiler.Syntax.SynTupleTypeSegment: FSharp.Compiler.Syntax.SynTupleTypeSegment NewSlash(FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynTupleTypeSegment: FSharp.Compiler.Syntax.SynTupleTypeSegment NewStar(FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynTupleTypeSegment: FSharp.Compiler.Syntax.SynTupleTypeSegment NewType(FSharp.Compiler.Syntax.SynType) +FSharp.Compiler.Syntax.SynTupleTypeSegment: FSharp.Compiler.Syntax.SynTupleTypeSegment+Slash +FSharp.Compiler.Syntax.SynTupleTypeSegment: FSharp.Compiler.Syntax.SynTupleTypeSegment+Star +FSharp.Compiler.Syntax.SynTupleTypeSegment: FSharp.Compiler.Syntax.SynTupleTypeSegment+Tags +FSharp.Compiler.Syntax.SynTupleTypeSegment: FSharp.Compiler.Syntax.SynTupleTypeSegment+Type +FSharp.Compiler.Syntax.SynTupleTypeSegment: FSharp.Compiler.Text.Range Range +FSharp.Compiler.Syntax.SynTupleTypeSegment: FSharp.Compiler.Text.Range get_Range() +FSharp.Compiler.Syntax.SynTupleTypeSegment: Int32 Tag +FSharp.Compiler.Syntax.SynTupleTypeSegment: Int32 get_Tag() +FSharp.Compiler.Syntax.SynTupleTypeSegment: System.String ToString() FSharp.Compiler.Syntax.SynTypar FSharp.Compiler.Syntax.SynTypar: Boolean get_isCompGen() FSharp.Compiler.Syntax.SynTypar: Boolean isCompGen @@ -8477,8 +8505,8 @@ FSharp.Compiler.Syntax.SynType+Tuple: Boolean get_isStruct() FSharp.Compiler.Syntax.SynType+Tuple: Boolean isStruct FSharp.Compiler.Syntax.SynType+Tuple: FSharp.Compiler.Text.Range get_range() FSharp.Compiler.Syntax.SynType+Tuple: FSharp.Compiler.Text.Range range -FSharp.Compiler.Syntax.SynType+Tuple: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.Boolean,FSharp.Compiler.Syntax.SynType]] elementTypes -FSharp.Compiler.Syntax.SynType+Tuple: Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.Boolean,FSharp.Compiler.Syntax.SynType]] get_elementTypes() +FSharp.Compiler.Syntax.SynType+Tuple: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynTupleTypeSegment] get_path() +FSharp.Compiler.Syntax.SynType+Tuple: Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynTupleTypeSegment] path FSharp.Compiler.Syntax.SynType+Var: FSharp.Compiler.Syntax.SynTypar get_typar() FSharp.Compiler.Syntax.SynType+Var: FSharp.Compiler.Syntax.SynTypar typar FSharp.Compiler.Syntax.SynType+Var: FSharp.Compiler.Text.Range get_range() @@ -8537,7 +8565,7 @@ FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewParen(FSharp.C 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) -FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewTuple(Boolean, Microsoft.FSharp.Collections.FSharpList`1[System.Tuple`2[System.Boolean,FSharp.Compiler.Syntax.SynType]], FSharp.Compiler.Text.Range) +FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewTuple(Boolean, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynTupleTypeSegment], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewVar(FSharp.Compiler.Syntax.SynTypar, FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType NewWithGlobalConstraints(FSharp.Compiler.Syntax.SynType, Microsoft.FSharp.Collections.FSharpList`1[FSharp.Compiler.Syntax.SynTypeConstraint], FSharp.Compiler.Text.Range) FSharp.Compiler.Syntax.SynType: FSharp.Compiler.Syntax.SynType+Anon diff --git a/tests/service/ServiceUntypedParseTests.fs b/tests/service/ServiceUntypedParseTests.fs index 9917ec23d27..19716749a39 100644 --- a/tests/service/ServiceUntypedParseTests.fs +++ b/tests/service/ServiceUntypedParseTests.fs @@ -12,6 +12,7 @@ open FsUnit open FSharp.Compiler.EditorServices open FSharp.Compiler.Service.Tests.Common open FSharp.Compiler.Syntax +open FSharp.Compiler.SyntaxTreeOps open FSharp.Compiler.Text open FSharp.Compiler.Text.Position open NUnit.Framework @@ -156,8 +157,8 @@ let rec getParenTypes (synType: SynType): SynType list = yield! getParenTypes argType yield! getParenTypes returnType - | SynType.Tuple (_, types, _) -> - for _, synType in types do + | SynType.Tuple(path = segment) -> + for synType in getTypeFromTuplePath segment do yield! getParenTypes synType | SynType.AnonRecd (_, fields, _) -> diff --git a/tests/service/SyntaxTreeTests/MeasureTests.fs b/tests/service/SyntaxTreeTests/MeasureTests.fs index 0ccbf5a6d5d..0e618693df9 100644 --- a/tests/service/SyntaxTreeTests/MeasureTests.fs +++ b/tests/service/SyntaxTreeTests/MeasureTests.fs @@ -46,4 +46,80 @@ let ``SynMeasure.Paren has correct range`` () = Assert.AreEqual("staff", staffIdent.idText) Assert.AreEqual("weeks", weeksIdent.idText) assertRange (2, 9) (2, 22) mParen - | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" \ No newline at end of file + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +let private (|TypeName|_|) t = + match t with + | SynType.LongIdent(SynLongIdent([ident], _, _)) -> Some ident.idText + | _ -> None + +[] +let ``SynType.Tuple in measure type with no slashes`` () = + let parseResults = + getParseResults + """ +[] type X = Y * Z +""" + + match parseResults with + | ParsedInput.ImplFile (ParsedImplFileInput (modules = [ SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Types(typeDefns = [ + SynTypeDefn(typeRepr = + SynTypeDefnRepr.Simple(simpleRepr = + SynTypeDefnSimpleRepr.TypeAbbrev(rhsType = + SynType.Tuple(false, [ SynTupleTypeSegment.Type (TypeName "Y") + SynTupleTypeSegment.Star mStar + SynTupleTypeSegment.Type (TypeName "Z") ], mTuple)))) + ]) + ]) ])) -> + assertRange (2, 23) (2, 24) mStar + assertRange (2, 21) (2, 26) mTuple + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +[] +let ``SynType.Tuple in measure type with leading slash`` () = + let parseResults = + getParseResults + """ +[] type X = / second +""" + + match parseResults with + | ParsedInput.ImplFile (ParsedImplFileInput (modules = [ SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Types(typeDefns = [ + SynTypeDefn(typeRepr = + SynTypeDefnRepr.Simple(simpleRepr = + SynTypeDefnSimpleRepr.TypeAbbrev(rhsType = + SynType.Tuple(false, [ SynTupleTypeSegment.Slash mSlash + SynTupleTypeSegment.Type (TypeName "second") ], mTuple)))) + ]) + ]) ])) -> + assertRange (2, 21) (2, 22) mSlash + assertRange (2, 21) (2, 29) mTuple + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}" + +[] +let ``SynType.Tuple in measure type with start and slash`` () = + let parseResults = + getParseResults + """ +[] type R = X * Y / Z +""" + + match parseResults with + | ParsedInput.ImplFile (ParsedImplFileInput (modules = [ SynModuleOrNamespace.SynModuleOrNamespace(decls = [ + SynModuleDecl.Types(typeDefns = [ + SynTypeDefn(typeRepr = + SynTypeDefnRepr.Simple(simpleRepr = + SynTypeDefnSimpleRepr.TypeAbbrev(rhsType = + SynType.Tuple(false, [ SynTupleTypeSegment.Type (TypeName "X") + SynTupleTypeSegment.Star msStar + SynTupleTypeSegment.Type (TypeName "Y") + SynTupleTypeSegment.Slash msSlash + SynTupleTypeSegment.Type (TypeName "Z") ], mTuple)))) + ]) + ]) ])) -> + assertRange (2, 23) (2, 24) msStar + assertRange (2, 21) (2, 30) mTuple + assertRange (2, 27) (2, 28) msSlash + | _ -> Assert.Fail $"Could not get valid AST, got {parseResults}"