Skip to content

Commit

Permalink
Add trivia information to SynConst.Measure (#15614)
Browse files Browse the repository at this point in the history
* initial commit

* adjust existing baseline files

* update service surface area baselines

* - add range to SynMeasure.One
 - add tests
 - update baselines

* make measure1 of SynMeasure.Divide optional

* - add range to SynRationalConst.Integer
- add test
- update surface baselines

* format

* - add numeratorRange and denominatorRange to SynRationalConst.Rational
- add test and put other tests inside a module
- update baselines

* - extend SynRationalConst.Negate to also have a range
- add test
- update baselines

* fix range of SynRationalConst.Negate to really include the '-'

* add another test for SynRationalConst.Negate range with space between hat and MINUS

* don't include minus in range of SynRationalConst.Integer in rationalConstant rule
  • Loading branch information
dawedawe authored Jul 21, 2023
1 parent f1e1af3 commit 7b5e128
Show file tree
Hide file tree
Showing 32 changed files with 399 additions and 100 deletions.
44 changes: 23 additions & 21 deletions src/Compiler/Checking/CheckExpressions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -754,16 +754,16 @@ let ForNewConstructors tcSink (env: TcEnv) mObjTy methodName meths =
/// Typecheck rational constant terms in units-of-measure exponents
let rec TcSynRationalConst c =
match c with
| SynRationalConst.Integer i -> intToRational i
| SynRationalConst.Negate c2 -> NegRational (TcSynRationalConst c2)
| SynRationalConst.Rational(p, q, _) -> DivRational (intToRational p) (intToRational q)
| SynRationalConst.Integer(value = i) -> intToRational i
| SynRationalConst.Negate(rationalConst = c2) -> NegRational (TcSynRationalConst c2)
| SynRationalConst.Rational(numerator = p; denominator = q) -> DivRational (intToRational p) (intToRational q)

/// Typecheck constant terms in expressions and patterns
let TcConst (cenv: cenv) (overallTy: TType) m env synConst =
let g = cenv.g
let rec tcMeasure ms =
match ms with
| SynMeasure.One -> Measure.One
| SynMeasure.One _ -> Measure.One
| SynMeasure.Named(tc, m) ->
let ad = env.eAccessRights
let _, tcref = ForceRaise(ResolveTypeLongIdent cenv.tcSink cenv.nameResolver ItemOccurence.Use OpenQualified env.eNameResEnv ad tc TypeNameResolutionStaticArgsInfo.DefiniteEmpty PermitDirectReferenceToGeneratedType.No)
Expand All @@ -775,9 +775,11 @@ let TcConst (cenv: cenv) (overallTy: TType) m env synConst =
| SynMeasure.Product(ms1, ms2, _) -> Measure.Prod(tcMeasure ms1, tcMeasure ms2)
| SynMeasure.Divide(ms1, (SynMeasure.Seq (_ :: _ :: _, _) as ms2), m) ->
warning(Error(FSComp.SR.tcImplicitMeasureFollowingSlash(), m))
Measure.Prod(tcMeasure ms1, Measure.Inv (tcMeasure ms2))
let factor1 = ms1 |> Option.defaultValue (SynMeasure.One Range.Zero)
Measure.Prod(tcMeasure factor1, Measure.Inv (tcMeasure ms2))
| SynMeasure.Divide(ms1, ms2, _) ->
Measure.Prod(tcMeasure ms1, Measure.Inv (tcMeasure ms2))
let factor1 = ms1 |> Option.defaultValue (SynMeasure.One Range.Zero)
Measure.Prod(tcMeasure factor1, Measure.Inv (tcMeasure ms2))
| SynMeasure.Seq(mss, _) -> ProdMeasures (List.map tcMeasure mss)
| SynMeasure.Anon _ -> error(Error(FSComp.SR.tcUnexpectedMeasureAnon(), m))
| SynMeasure.Var(_, m) -> error(Error(FSComp.SR.tcNonZeroConstantCannotHaveGenericUnit(), m))
Expand All @@ -788,10 +790,10 @@ let TcConst (cenv: cenv) (overallTy: TType) m env synConst =
let unifyMeasureArg iszero tcr =
let measureTy =
match synConst with
| SynConst.Measure(_, _, SynMeasure.Anon _) ->
| SynConst.Measure(synMeasure = SynMeasure.Anon _) ->
(mkAppTy tcr [TType_measure (Measure.Var (NewAnonTypar (TyparKind.Measure, m, TyparRigidity.Anon, (if iszero then TyparStaticReq.None else TyparStaticReq.HeadType), TyparDynamicReq.No)))])

| SynConst.Measure(_, _, ms) -> mkAppTy tcr [TType_measure (tcMeasure ms)]
| SynConst.Measure(synMeasure = ms) -> mkAppTy tcr [TType_measure (tcMeasure ms)]
| _ -> mkAppTy tcr [TType_measure Measure.One]
unif measureTy

Expand Down Expand Up @@ -844,43 +846,43 @@ let TcConst (cenv: cenv) (overallTy: TType) m env synConst =
| SynConst.UIntPtr i ->
unif g.unativeint_ty
Const.UIntPtr i
| SynConst.Measure(SynConst.Single f, _, _) ->
| SynConst.Measure(constant = SynConst.Single f) ->
unifyMeasureArg (f=0.0f) g.pfloat32_tcr
Const.Single f
| SynConst.Measure(SynConst.Double f, _, _) ->
| SynConst.Measure(constant = SynConst.Double f) ->
unifyMeasureArg (f=0.0) g.pfloat_tcr
Const.Double f
| SynConst.Measure(SynConst.Decimal f, _, _) ->
| SynConst.Measure(constant = SynConst.Decimal f) ->
unifyMeasureArg false g.pdecimal_tcr
Const.Decimal f
| SynConst.Measure(SynConst.SByte i, _, _) ->
| SynConst.Measure(constant = SynConst.SByte i)->
unifyMeasureArg (i=0y) g.pint8_tcr
Const.SByte i
| SynConst.Measure(SynConst.Int16 i, _, _) ->
| SynConst.Measure(constant = SynConst.Int16 i) ->
unifyMeasureArg (i=0s) g.pint16_tcr
Const.Int16 i
| SynConst.Measure(SynConst.Int32 i, _, _) ->
| SynConst.Measure(constant = SynConst.Int32 i) ->
unifyMeasureArg (i=0) g.pint_tcr
Const.Int32 i
| SynConst.Measure(SynConst.Int64 i, _, _) ->
| SynConst.Measure(constant = SynConst.Int64 i) ->
unifyMeasureArg (i=0L) g.pint64_tcr
Const.Int64 i
| SynConst.Measure(SynConst.IntPtr i, _, _) when expandedMeasurablesEnabled ->
| SynConst.Measure(constant = SynConst.IntPtr i) when expandedMeasurablesEnabled ->
unifyMeasureArg (i=0L) g.pnativeint_tcr
Const.IntPtr i
| SynConst.Measure(SynConst.Byte i, _, _) when expandedMeasurablesEnabled ->
| SynConst.Measure(constant = SynConst.Byte i) when expandedMeasurablesEnabled ->
unifyMeasureArg (i=0uy) g.puint8_tcr
Const.Byte i
| SynConst.Measure(SynConst.UInt16 i, _, _) when expandedMeasurablesEnabled ->
| SynConst.Measure(constant = SynConst.UInt16 i) when expandedMeasurablesEnabled ->
unifyMeasureArg (i=0us) g.puint16_tcr
Const.UInt16 i
| SynConst.Measure(SynConst.UInt32 i, _, _) when expandedMeasurablesEnabled ->
| SynConst.Measure(constant = SynConst.UInt32 i) when expandedMeasurablesEnabled ->
unifyMeasureArg (i=0u) g.puint_tcr
Const.UInt32 i
| SynConst.Measure(SynConst.UInt64 i, _, _) when expandedMeasurablesEnabled ->
| SynConst.Measure(constant = SynConst.UInt64 i) when expandedMeasurablesEnabled ->
unifyMeasureArg (i=0UL) g.puint64_tcr
Const.UInt64 i
| SynConst.Measure(SynConst.UIntPtr i, _, _) when expandedMeasurablesEnabled ->
| SynConst.Measure(constant = SynConst.UIntPtr i) when expandedMeasurablesEnabled ->
unifyMeasureArg (i=0UL) g.punativeint_tcr
Const.UIntPtr i
| SynConst.Char c ->
Expand Down
6 changes: 3 additions & 3 deletions src/Compiler/Service/ServiceInterfaceStubGenerator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ type InterfaceData =
| InterfaceData.ObjExpr (StripParenTypes ty, _) ->
let rec (|RationalConst|) =
function
| SynRationalConst.Integer i -> string i
| SynRationalConst.Rational (numerator, denominator, _) -> sprintf "(%i/%i)" numerator denominator
| SynRationalConst.Negate (RationalConst s) -> sprintf "- %s" s
| SynRationalConst.Integer (value = i) -> string i
| SynRationalConst.Rational (numerator = numerator; denominator = denominator) -> sprintf "(%i/%i)" numerator denominator
| SynRationalConst.Negate (rationalConst = (RationalConst s)) -> sprintf "- %s" s

let rec (|TypeIdent|_|) =
function
Expand Down
10 changes: 6 additions & 4 deletions src/Compiler/Service/ServiceParsedInputOps.fs
Original file line number Diff line number Diff line change
Expand Up @@ -1841,21 +1841,23 @@ module ParsedInput =
List.iter walkType ts
walkMemberSig sign
walkExpr e
| SynExpr.Const (SynConst.Measure (_, _, m), _) -> walkMeasure m
| SynExpr.Const(constant = SynConst.Measure (synMeasure = m)) -> walkMeasure m
| _ -> ()

and walkMeasure measure =
match measure with
| SynMeasure.Product (m1, m2, _)
| SynMeasure.Divide (m1, m2, _) ->
| SynMeasure.Product (m1, m2, _) ->
walkMeasure m1
walkMeasure m2
| SynMeasure.Divide (m1, m2, _) ->
m1 |> Option.iter walkMeasure
walkMeasure m2
| SynMeasure.Named (longIdent, _) -> addLongIdent longIdent
| SynMeasure.Seq (ms, _) -> List.iter walkMeasure ms
| SynMeasure.Paren (m, _)
| SynMeasure.Power (m, _, _) -> walkMeasure m
| SynMeasure.Var (ty, _) -> walkTypar ty
| SynMeasure.One
| SynMeasure.One _
| SynMeasure.Anon _ -> ()

and walkSimplePat spat =
Expand Down
12 changes: 6 additions & 6 deletions src/Compiler/SyntaxTree/SyntaxTree.fs
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ type SynConst =

| UInt16s of uint16[]

| Measure of constant: SynConst * constantRange: range * SynMeasure
| Measure of constant: SynConst * constantRange: range * synMeasure: SynMeasure * trivia: SynMeasureConstantTrivia

| SourceIdentifier of constant: string * value: string * range: range

Expand All @@ -178,11 +178,11 @@ type SynMeasure =

| Seq of measures: SynMeasure list * range: range

| Divide of measure1: SynMeasure * measure2: SynMeasure * range: range
| Divide of measure1: SynMeasure option * measure2: SynMeasure * range: range

| Power of measure: SynMeasure * power: SynRationalConst * range: range

| One
| One of range: range

| Anon of range: range

Expand All @@ -193,11 +193,11 @@ type SynMeasure =
[<NoEquality; NoComparison; RequireQualifiedAccess>]
type SynRationalConst =

| Integer of value: int32
| Integer of value: int32 * range: range

| Rational of numerator: int32 * denominator: int32 * range: range
| Rational of numerator: int32 * numeratorRange: range * denominator: int32 * denominatorRange: range * range: range

| Negate of SynRationalConst
| Negate of rationalConst: SynRationalConst * range: range

[<RequireQualifiedAccess>]
type SynAccess =
Expand Down
12 changes: 6 additions & 6 deletions src/Compiler/SyntaxTree/SyntaxTree.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ type SynConst =
| UInt16s of uint16[]

/// Old comment: "we never iterate, so the const here is not another SynConst.Measure"
| Measure of constant: SynConst * constantRange: range * SynMeasure
| Measure of constant: SynConst * constantRange: range * synMeasure: SynMeasure * trivia: SynMeasureConstantTrivia

/// Source Line, File, and Path Identifiers
/// Containing both the original value as the evaluated value.
Expand All @@ -193,13 +193,13 @@ type SynMeasure =
| Seq of measures: SynMeasure list * range: range

/// A division of two units of measure, e.g. 'kg / m'
| Divide of measure1: SynMeasure * measure2: SynMeasure * range: range
| Divide of measure1: SynMeasure option * measure2: SynMeasure * range: range

/// A power of a unit of measure, e.g. 'kg ^ 2'
| Power of measure: SynMeasure * power: SynRationalConst * range: range

/// The '1' unit of measure
| One
| One of range: range

/// An anonymous (inferred) unit of measure
| Anon of range: range
Expand All @@ -214,11 +214,11 @@ type SynMeasure =
[<NoEquality; NoComparison; RequireQualifiedAccess>]
type SynRationalConst =

| Integer of value: int32
| Integer of value: int32 * range: range

| Rational of numerator: int32 * denominator: int32 * range: range
| Rational of numerator: int32 * numeratorRange: range * denominator: int32 * denominatorRange: range * range: range

| Negate of SynRationalConst
| Negate of rationalConst: SynRationalConst * range: range

/// Represents an accessibility modifier in F# syntax
[<RequireQualifiedAccess>]
Expand Down
7 changes: 7 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTrivia.fs
Original file line number Diff line number Diff line change
Expand Up @@ -395,3 +395,10 @@ type SynMemberSigMemberTrivia =
}

static member Zero: SynMemberSigMemberTrivia = { GetSetKeywords = None }

[<NoEquality; NoComparison>]
type SynMeasureConstantTrivia =
{
LessRange: range
GreaterRange: range
}
6 changes: 6 additions & 0 deletions src/Compiler/SyntaxTree/SyntaxTrivia.fsi
Original file line number Diff line number Diff line change
Expand Up @@ -513,3 +513,9 @@ type SynMemberSigMemberTrivia =
}

static member Zero: SynMemberSigMemberTrivia

/// Represents additional information for SynConst.Measure
[<NoEquality; NoComparison>]
type SynMeasureConstantTrivia =
{ LessRange: range
GreaterRange: range }
52 changes: 37 additions & 15 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -3279,25 +3279,25 @@ rationalConstant:
{ if $2 <> "/" then reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnexpectedOperatorForUnitOfMeasure())
if fst $3 = 0 then reportParseErrorAt (rhs parseState 3) (FSComp.SR.parsIllegalDenominatorForMeasureExponent())
if (snd $1) || (snd $3) then errorR(Error(FSComp.SR.lexOutsideThirtyTwoBitSigned(), lhs parseState))
SynRationalConst.Rational(fst $1, fst $3, lhs parseState) }
SynRationalConst.Rational(fst $1, rhs parseState 1, fst $3, rhs parseState 3, lhs parseState) }

| MINUS INT32 INFIX_STAR_DIV_MOD_OP INT32
{ if $3 <> "/" then reportParseErrorAt (rhs parseState 3) (FSComp.SR.parsUnexpectedOperatorForUnitOfMeasure())
if fst $4 = 0 then reportParseErrorAt (rhs parseState 4) (FSComp.SR.parsIllegalDenominatorForMeasureExponent())
if (snd $2) || (snd $4) then errorR(Error(FSComp.SR.lexOutsideThirtyTwoBitSigned(), lhs parseState))
SynRationalConst.Negate(SynRationalConst.Rational(fst $2, fst $4, lhs parseState)) }
SynRationalConst.Negate(SynRationalConst.Rational(fst $2, rhs parseState 2, fst $4, rhs parseState 4, lhs parseState), lhs parseState) }

| INT32
{ if snd $1 then errorR(Error(FSComp.SR.lexOutsideThirtyTwoBitSigned(), lhs parseState))
SynRationalConst.Integer(fst $1) }
SynRationalConst.Integer(fst $1, lhs parseState) }

| MINUS INT32
{ if snd $2 then errorR(Error(FSComp.SR.lexOutsideThirtyTwoBitSigned(), lhs parseState))
SynRationalConst.Negate(SynRationalConst.Integer(fst $2)) }
SynRationalConst.Negate(SynRationalConst.Integer(fst $2, rhs parseState 2), lhs parseState) }

atomicUnsignedRationalConstant:
| INT32 { if snd $1 then errorR(Error(FSComp.SR.lexOutsideThirtyTwoBitSigned(), lhs parseState))
SynRationalConst.Integer(fst $1) }
SynRationalConst.Integer(fst $1, lhs parseState) }

| LPAREN rationalConstant rparen
{ $2 }
Expand All @@ -3306,14 +3306,17 @@ atomicRationalConstant:
| atomicUnsignedRationalConstant { $1 }

| MINUS atomicUnsignedRationalConstant
{ SynRationalConst.Negate($2) }
{ SynRationalConst.Negate($2, lhs parseState) }

constant:
| rawConstant
{ $1, rhs parseState 1 }

| rawConstant HIGH_PRECEDENCE_TYAPP measureTypeArg
{ SynConst.Measure($1, rhs parseState 1, $3), lhs parseState }
{ let synMeasure, trivia = $3
let mConstant = rhs parseState 1
let m = unionRanges mConstant trivia.GreaterRange
SynConst.Measure($1, rhs parseState 1, synMeasure, trivia), m }

bindingPattern:
| headBindingPattern
Expand Down Expand Up @@ -5857,7 +5860,11 @@ appTypeCon:
appTypeConPower:
| appTypeCon INFIX_AT_HAT_OP atomicRationalConstant
{ if $2 <> "^" && $2 <> "^-" then reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnexpectedInfixOperator())
if $2 = "^-" then SynType.MeasurePower($1, SynRationalConst.Negate($3), lhs parseState)
if $2 = "^-" then
let afterMinus = (rhs parseState 2).EndRange
let beforeMinus = mkRange afterMinus.FileName (mkPos afterMinus.EndLine (afterMinus.EndColumn - 1)) afterMinus.End
let m = unionRanges beforeMinus (rhs parseState 3) // include MINUS in Negate range
SynType.MeasurePower($1, SynRationalConst.Negate($3, m), lhs parseState)
else SynType.MeasurePower($1, $3, lhs parseState) }

| appTypeCon
Expand Down Expand Up @@ -6014,7 +6021,11 @@ powerType:

| atomTypeOrAnonRecdType INFIX_AT_HAT_OP atomicRationalConstant
{ if $2 <> "^" && $2 <> "^-" then reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnexpectedInfixOperator())
if $2 = "^-" then SynType.MeasurePower($1, SynRationalConst.Negate($3), lhs parseState)
if $2 = "^-" then
let afterMinus = (rhs parseState 2).EndRange
let beforeMinus = mkRange afterMinus.FileName (mkPos afterMinus.EndLine (afterMinus.EndColumn - 1)) afterMinus.End
let m = unionRanges beforeMinus (rhs parseState 3) // include MINUS in Negate range
SynType.MeasurePower($1, SynRationalConst.Negate($3, m), lhs parseState)
else SynType.MeasurePower($1, $3, lhs parseState) }


Expand Down Expand Up @@ -6207,10 +6218,16 @@ dummyTypeArg:

measureTypeArg:
| LESS measureTypeExpr GREATER
{ $2 }
{ let mLess = rhs parseState 1
let mGreater = rhs parseState 3
let trivia = { LessRange = mLess; GreaterRange = mGreater }
$2, trivia }

| LESS UNDERSCORE GREATER
{ SynMeasure.Anon(lhs parseState) }
{ let mLess = rhs parseState 1
let mGreater = rhs parseState 3
let trivia = { LessRange = mLess; GreaterRange = mGreater }
SynMeasure.Anon(rhs parseState 2), trivia }

measureTypeAtom:
| path
Expand All @@ -6229,12 +6246,17 @@ measureTypePower:

| measureTypeAtom INFIX_AT_HAT_OP atomicRationalConstant
{ if $2 <> "^" && $2 <> "^-" then reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnexpectedOperatorForUnitOfMeasure())
if $2 = "^-" then SynMeasure.Power($1, SynRationalConst.Negate($3), lhs parseState)
if $2 = "^-" then
let afterMinus = (rhs parseState 2).EndRange
let beforeMinus = mkRange afterMinus.FileName (mkPos afterMinus.EndLine (afterMinus.EndColumn - 1)) afterMinus.End
let m = unionRanges beforeMinus (rhs parseState 3) // include MINUS in Negate range
SynMeasure.Power($1, SynRationalConst.Negate($3, m), lhs parseState)
else SynMeasure.Power($1, $3, lhs parseState) }

| INT32
{ if fst $1 <> 1 then reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnexpectedIntegerLiteralForUnitOfMeasure())
SynMeasure.One }
let m = rhs parseState 1
SynMeasure.One(m) }

measureTypeSeq:
| measureTypePower
Expand All @@ -6253,11 +6275,11 @@ measureTypeExpr:
| measureTypeExpr INFIX_STAR_DIV_MOD_OP measureTypeExpr
{ if $2 <> "*" && $2 <> "/" then reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsUnexpectedOperatorForUnitOfMeasure())
if $2 = "*" then SynMeasure.Product($1, $3, lhs parseState)
else SynMeasure.Divide($1, $3, lhs parseState) }
else SynMeasure.Divide(Some $1, $3, lhs parseState) }

| INFIX_STAR_DIV_MOD_OP measureTypeExpr
{ if $1 <> "/" then reportParseErrorAt (rhs parseState 1) (FSComp.SR.parsUnexpectedOperatorForUnitOfMeasure())
SynMeasure.Divide(SynMeasure.One, $2, lhs parseState) }
SynMeasure.Divide(None, $2, lhs parseState) }

typar:
| QUOTE ident
Expand Down
Loading

0 comments on commit 7b5e128

Please sign in to comment.