Skip to content

Fix 16696 #18607

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 35 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
1799aaf
make attribute targets mismatches a warning and not an error.
edgarfgp Apr 23, 2025
55507e9
release notes
edgarfgp Apr 23, 2025
1738018
update tests
edgarfgp Apr 23, 2025
65f5bb6
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 24, 2025
0c97b9d
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 27, 2025
6f2b706
update baselines
edgarfgp Apr 29, 2025
e8f1bb0
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 29, 2025
75d8f5e
Update baselines
edgarfgp Apr 29, 2025
4f2e97e
Merge branch 'fix-attr-targets' of github.com:edgarfgp/fsharp into fi…
edgarfgp Apr 29, 2025
63be5d5
Merge branch 'main' into fix-attr-targets
edgarfgp Apr 30, 2025
4248f2a
Move attribute form logic to an AP
edgarfgp Apr 30, 2025
cc96217
Merge branch 'main' into fix-attr-targets
edgarfgp May 1, 2025
e270b88
Merge branch 'main' into fix-attr-targets
edgarfgp May 1, 2025
e0cc65a
Merge branch 'main' into fix-attr-targets
edgarfgp May 2, 2025
1e29d58
Merge branch 'main' into fix-attr-targets
edgarfgp May 5, 2025
1470bf9
Merge branch 'main' into fix-attr-targets
edgarfgp May 6, 2025
8988215
Merge branch 'main' into fix-attr-targets
edgarfgp May 7, 2025
74712e8
Merge branch 'main' into fix-attr-targets
edgarfgp May 12, 2025
967c4a9
Merge branch 'main' of github.com:edgarfgp/fsharp
edgarfgp May 13, 2025
a30cef4
Merge branch 'dotnet:main' into main
edgarfgp May 22, 2025
5fa0480
Merge branch 'dotnet:main' into main
edgarfgp May 24, 2025
64dfa8c
Add add failing test
edgarfgp May 24, 2025
81c0bc9
Update lexer to allow (=$) as operator
edgarfgp May 24, 2025
2f0aaaa
Update tests
edgarfgp May 24, 2025
92f5b3c
update lex.fsl
edgarfgp May 24, 2025
db0c138
update test
edgarfgp May 24, 2025
e690363
WIP
edgarfgp May 25, 2025
0f56f09
Adding a new parsing rule
edgarfgp May 25, 2025
2076816
update ExprInterpolatedString test
edgarfgp May 25, 2025
02e73e7
update tests
edgarfgp May 25, 2025
6fa3992
update more tests
edgarfgp May 25, 2025
d8804e0
update more tests
edgarfgp May 25, 2025
3a9724a
more syntax tree tests
edgarfgp May 25, 2025
ba4bec1
more tests
edgarfgp May 25, 2025
3fd1397
Merge branch 'main' into fix-16696
edgarfgp May 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/Compiler/lex.fsl
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,11 @@ let checkExprOp (lexbuf:UnicodeLexing.Lexbuf) =
deprecatedWithError (FSComp.SR.lexCharNotAllowedInOperatorNames(":")) lexbuf.LexemeRange
if lexbuf.LexemeContains '$' then
deprecatedWithError (FSComp.SR.lexCharNotAllowedInOperatorNames("$")) lexbuf.LexemeRange


let checkExprEqualDollarOp (lexbuf:UnicodeLexing.Lexbuf) =
if lexbuf.LexemeContains ':' then
deprecatedWithError (FSComp.SR.lexCharNotAllowedInOperatorNames(":")) lexbuf.LexemeRange

let checkExprGreaterColonOp (lexbuf:UnicodeLexing.Lexbuf) =
if lexbuf.LexemeContains '$' then
deprecatedWithError (FSComp.SR.lexCharNotAllowedInOperatorNames("$")) lexbuf.LexemeRange
Expand Down Expand Up @@ -996,7 +1000,9 @@ rule token (args: LexArgs) (skip: bool) = parse

| ignored_op_char* ('@'|'^') op_char* { checkExprOp lexbuf; INFIX_AT_HAT_OP(lexeme lexbuf) }

| ignored_op_char* ('=' | "!=" | '<' | '$') op_char* { checkExprOp lexbuf; INFIX_COMPARE_OP(lexeme lexbuf) }
| ignored_op_char* ("!=" | '<' | '$') op_char* { checkExprOp lexbuf; INFIX_COMPARE_OP(lexeme lexbuf) }

| ignored_op_char* ('=') op_char* { checkExprEqualDollarOp lexbuf; INFIX_COMPARE_OP(lexeme lexbuf) }

| ignored_op_char* ('>') op_char* { checkExprGreaterColonOp lexbuf; INFIX_COMPARE_OP(lexeme lexbuf) }

Expand Down
55 changes: 55 additions & 0 deletions src/Compiler/pars.fsy
Original file line number Diff line number Diff line change
Expand Up @@ -3332,6 +3332,61 @@ localBinding:
mkSynBinding (xmlDoc, bindingPat) (vis, Option.isSome $1, Option.isSome $2, mWholeBindLhs, spBind, optReturnType, expr, mRhs, opts, attrs, None, trivia))
localBindingRange, localBindingBuilder }

| opt_inline opt_mutable bindingPattern opt_topReturnTypeWithTypeConstraints INFIX_COMPARE_OP string
{ let op = $5
if op <> "=$" then
reportParseErrorAt (rhs parseState 5) (FSComp.SR.parsUnexpectedInfixOperator())

let s, synStringKind = $6
let mString = rhs parseState 6
let mInfixOp = rhs parseState 5

let mDollarStart = mkRange mInfixOp.FileName (mkPos mInfixOp.StartLine (mInfixOp.StartColumn + 1)) mInfixOp.End
let mInterp = unionRanges mDollarStart mString
let parts = [ SynInterpolatedStringPart.String(s, mString) ]
let expr = SynExpr.InterpolatedString(parts, synStringKind, mInterp)

let mEquals = mkRange mInfixOp.FileName mInfixOp.Start (mkPos mInfixOp.StartLine (mInfixOp.StartColumn + 1))
let mRhs = expr.Range
let optReturnType = $4
let bindingPat, mBindLhs = $3
let localBindingRange = unionRanges (rhs2 parseState 1 5) mRhs
let localBindingBuilder =
(fun xmlDoc attrs vis (leadingKeyword: SynLeadingKeyword) ->
let mWhole = (unionRanges leadingKeyword.Range mRhs, attrs) ||> unionRangeWithListBy (fun (a: SynAttributeList) -> a.Range)
let spBind = if IsDebugPointBinding bindingPat expr then DebugPointAtBinding.Yes mWhole else DebugPointAtBinding.NoneAtLet
let mWholeBindLhs = (mBindLhs, attrs) ||> unionRangeWithListBy (fun (a: SynAttributeList) -> a.Range)
let trivia: SynBindingTrivia = { LeadingKeyword = leadingKeyword; InlineKeyword = $1; EqualsRange = Some mEquals }
mkSynBinding (xmlDoc, bindingPat) (vis, Option.isSome $1, Option.isSome $2, mWholeBindLhs, spBind, optReturnType, expr, mRhs, [], attrs, None, trivia))
localBindingRange, localBindingBuilder }

| opt_inline opt_mutable bindingPattern opt_topReturnTypeWithTypeConstraints INFIX_COMPARE_OP interpolatedString
{ let op = $5
if op <> "=$" then
reportParseErrorAt (rhs parseState 5) (FSComp.SR.parsUnexpectedInfixOperator())

let parts, synStringKind = $6
let mInfixOp = rhs parseState 5
let mString = rhs parseState 6

let mDollarStart = mkRange mInfixOp.FileName (mkPos mInfixOp.StartLine (mInfixOp.StartColumn + 1)) mInfixOp.End
let mInterp = unionRanges mDollarStart mString
let expr = SynExpr.InterpolatedString(parts, synStringKind, mInterp)

let mEquals = mkRange mInfixOp.FileName mInfixOp.Start (mkPos mInfixOp.StartLine (mInfixOp.StartColumn + 1))
let mRhs = expr.Range
let optReturnType = $4
let bindingPat, mBindLhs = $3
let localBindingRange = unionRanges (rhs2 parseState 1 5) mRhs
let localBindingBuilder =
(fun xmlDoc attrs vis (leadingKeyword: SynLeadingKeyword) ->
let mWhole = (unionRanges leadingKeyword.Range mRhs, attrs) ||> unionRangeWithListBy (fun (a: SynAttributeList) -> a.Range)
let spBind = if IsDebugPointBinding bindingPat expr then DebugPointAtBinding.Yes mWhole else DebugPointAtBinding.NoneAtLet
let mWholeBindLhs = (mBindLhs, attrs) ||> unionRangeWithListBy (fun (a: SynAttributeList) -> a.Range)
let trivia: SynBindingTrivia = { LeadingKeyword = leadingKeyword; InlineKeyword = $1; EqualsRange = Some mEquals }
mkSynBinding (xmlDoc, bindingPat) (vis, Option.isSome $1, Option.isSome $2, mWholeBindLhs, spBind, optReturnType, expr, mRhs, [], attrs, None, trivia))
localBindingRange, localBindingBuilder }

| opt_inline opt_mutable bindingPattern opt_topReturnTypeWithTypeConstraints EQUALS error
{ let mWhole = rhs2 parseState 1 5
let mRhs = rhs parseState 5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ raise (new Exception("exit 1"))
EndLine = 37
EndColumn = 6 }
Message =
"Incomplete structured construct at or before this point in binding. Expected '=' or other token." }
"Incomplete structured construct at or before this point in binding. Expected infix operator, '=' or other token." }
{ Error = Error 10
Range = { StartLine = 46
StartColumn = 5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ printf $"%s{hello}"
|> withWarnOn 3579
|> typecheck
|> shouldSucceed

Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,7 @@ let z as
"(16,0--16,3): Unexpected syntax or possible incorrect indentation: this token is offside of context started at position (15:1). Try indenting this further. To continue using non-conforming indentation, pass the '--strict-indentation-' flag to the compiler, or set the language version to F# 7.";
"(17,16--17,17): Unexpected identifier in pattern. Expected '(' or other token.";
"(19,6--19,8): Expecting pattern";
"(20,0--20,0): Incomplete structured construct at or before this point in binding. Expected '=' or other token.";
"(20,0--20,0): Incomplete structured construct at or before this point in binding. Expected infix operator, '=' or other token.";
"(3,13--3,17): This expression was expected to have type 'int' but here has type 'bool'";
"(3,4--3,10): Incomplete pattern matches on this expression. For example, the value '0' may indicate a case not covered by the pattern(s).";
"(4,16--4,17): This expression was expected to have type 'bool' but here has type 'int'";
Expand Down Expand Up @@ -682,7 +682,7 @@ let z as =
dumpDiagnostics checkResults |> shouldEqual [
"(10,7--10,9): Unexpected keyword 'as' in binding";
"(10,5--10,6): Expecting pattern";
"(11,10--11,12): Unexpected keyword 'as' in binding. Expected '=' or other token.";
"(11,10--11,12): Unexpected keyword 'as' in binding. Expected infix operator, '=' or other token.";
"(12,6--12,8): Expecting pattern";
"(13,8--13,10): Unexpected keyword 'as' in binding";
"(14,8--14,10): Unexpected keyword 'as' in binding";
Expand Down Expand Up @@ -879,7 +879,7 @@ let :? z as
"(16,0--16,3): Unexpected syntax or possible incorrect indentation: this token is offside of context started at position (15:1). Try indenting this further. To continue using non-conforming indentation, pass the '--strict-indentation-' flag to the compiler, or set the language version to F# 7.";
"(17,19--17,20): Unexpected identifier in pattern. Expected '(' or other token.";
"(19,9--19,11): Expecting pattern";
"(20,0--20,0): Incomplete structured construct at or before this point in binding. Expected '=' or other token.";
"(20,0--20,0): Incomplete structured construct at or before this point in binding. Expected infix operator, '=' or other token.";
"(3,7--3,8): The type 'a' is not defined.";
"(3,4--3,8): This runtime coercion or type test from type 'a to 'b involves an indeterminate type based on information prior to this program point. Runtime type tests are not allowed on some types. Further type annotations are needed.";
"(4,7--4,8): The type 'b' is not defined.";
Expand Down Expand Up @@ -1086,7 +1086,7 @@ let as :? z =
dumpDiagnostics checkResults |> shouldEqual [
"(10,7--10,9): Unexpected keyword 'as' in binding";
"(10,5--10,6): Expecting pattern";
"(11,10--11,12): Unexpected keyword 'as' in binding. Expected '=' or other token.";
"(11,10--11,12): Unexpected keyword 'as' in binding. Expected infix operator, '=' or other token.";
"(12,6--12,8): Expecting pattern";
"(13,8--13,10): Unexpected keyword 'as' in binding";
"(14,8--14,10): Unexpected keyword 'as' in binding";
Expand Down Expand Up @@ -1141,7 +1141,7 @@ let y as ?z = 8
"""
dumpDiagnostics checkResults |> shouldEqual [
"(7,6--7,8): Expecting pattern";
"(7,9--7,11): Unexpected symbol '[<' in binding. Expected '=' or other token."
"(7,9--7,11): Unexpected symbol '[<' in binding. Expected infix operator, '=' or other token."
"(8,4--8,11): This is not a valid pattern"
"(8,4--8,16): Incomplete pattern matches on this expression."
"(9,9--9,16): This is not a valid pattern"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
#light

//<Expects id="FS0010" status="error">Unexpected keyword 'type' in binding</Expects>
//<Expects id="FS0010" status="error">Unexpected keyword 'class' in binding. Expected '=' or other token.</Expects>
//<Expects id="FS0010" status="error">Unexpected keyword 'class' in binding. Expected infix operator, '=' or other token.</Expects>

let type = 2

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// #Regression #Diagnostics
// Regression test for FSHARP1.0:2099
// Regression test for FSHARP1.0:2670
//<Expects id="FS0010" span="(18,50-18,52)" status="error">Unexpected symbol '<-' in binding. Expected '=' or other token.</Expects>
//<Expects id="FS0010" span="(18,50-18,52)" status="error">Unexpected symbol '<-' in binding. Expected infix operator, '=' or other token.</Expects>
//<Expects id="FS0588" span="(18,42-18,45)" status="error">The block following this 'let' is unfinished. Every code block is an expression and must have a result. 'let' cannot be the final code element in a block. Consider giving this block an explicit result.</Expects>
//<Expects status="notin">lambda</Expects>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// #Regression #NoMT #FSI
// Regression test for FSHARP1.0:5629
//<Expects status="error" span="(4,6)" id="FS0010">Incomplete structured construct at or before this point in binding. Expected '=' or other token.</Expects>
//<Expects status="error" span="(4,6)" id="FS0010">Incomplete structured construct at or before this point in binding. Expected infix operator, '=' or other token.</Expects>
let f;;
exit 1;;
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Module

C(Name="123")
C(Name=$"123")
C(Name= $"123")
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
ImplFile
(ParsedImplFileInput
("/root/Expression/ExprInterpolatedString 01.fs", false,
QualifiedNameOfFile Module, [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Expr
(App
(Atomic, false, Ident C,
Paren
(App
(NonAtomic, false,
App
(NonAtomic, true,
LongIdent
(false,
SynLongIdent
([op_Equality], [], [Some (OriginalNotation "=")]),
None, (3,6--3,7)), Ident Name, (3,2--3,7)),
Const (String ("123", Regular, (3,7--3,12)), (3,7--3,12)),
(3,2--3,12)), (3,1--3,2), Some (3,12--3,13), (3,1--3,13)),
(3,0--3,13)), (3,0--3,13));
Expr
(App
(Atomic, false, Ident C,
Paren
(App
(NonAtomic, false,
App
(NonAtomic, true,
LongIdent
(false,
SynLongIdent
([op_EqualsDollar], [],
[Some (OriginalNotation "=$")]), None,
(4,6--4,8)), Ident Name, (4,2--4,8)),
Const (String ("123", Regular, (4,8--4,13)), (4,8--4,13)),
(4,2--4,13)), (4,1--4,2), Some (4,13--4,14), (4,1--4,14)),
(4,0--4,14)), (4,0--4,14));
Expr
(App
(Atomic, false, Ident C,
Paren
(App
(NonAtomic, false,
App
(NonAtomic, true,
LongIdent
(false,
SynLongIdent
([op_Equality], [], [Some (OriginalNotation "=")]),
None, (5,6--5,7)), Ident Name, (5,2--5,7)),
InterpolatedString
([String ("123", (5,8--5,14))], Regular, (5,8--5,14)),
(5,2--5,14)), (5,1--5,2), Some (5,14--5,15), (5,1--5,15)),
(5,0--5,15)), (5,0--5,15))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--5,15), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
WarnDirectives = []
CodeComments = [] }, set []))
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Module

let a =$"123"
let b = $"123"
let x =$"hello {name}"
let x = $"hello {name}"
let y =$"value: {x + 1}"
let y = $"value: {x + 1}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
ImplFile
(ParsedImplFileInput
("/root/Expression/ExprInterpolatedString 02.fs", false,
QualifiedNameOfFile Module, [],
[SynModuleOrNamespace
([Module], false, NamedModule,
[Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((3,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Named (SynIdent (a, None), false, None, (3,4--3,5)), None,
InterpolatedString
([String ("123", (3,8--3,13))], Regular, (3,7--3,13)),
(3,4--3,5), Yes (3,0--3,13), { LeadingKeyword = Let (3,0--3,3)
InlineKeyword = None
EqualsRange = Some (3,6--3,7) })],
(3,0--3,13));
Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((4,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Named (SynIdent (b, None), false, None, (4,4--4,5)), None,
InterpolatedString
([String ("123", (4,8--4,14))], Regular, (4,8--4,14)),
(4,4--4,5), Yes (4,0--4,14), { LeadingKeyword = Let (4,0--4,3)
InlineKeyword = None
EqualsRange = Some (4,6--4,7) })],
(4,0--4,14));
Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((5,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Named (SynIdent (x, None), false, None, (5,4--5,5)), None,
InterpolatedString
([String ("hello {name}", (5,8--5,22))], Regular,
(5,7--5,22)), (5,4--5,5), Yes (5,0--5,22),
{ LeadingKeyword = Let (5,0--5,3)
InlineKeyword = None
EqualsRange = Some (5,6--5,7) })], (5,0--5,22));
Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((6,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Named (SynIdent (x, None), false, None, (6,4--6,5)), None,
InterpolatedString
([String ("hello ", (6,8--6,17));
FillExpr (Ident name, None); String ("", (6,21--6,23))],
Regular, (6,8--6,23)), (6,4--6,5), Yes (6,0--6,23),
{ LeadingKeyword = Let (6,0--6,3)
InlineKeyword = None
EqualsRange = Some (6,6--6,7) })], (6,0--6,23));
Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((7,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Named (SynIdent (y, None), false, None, (7,4--7,5)), None,
InterpolatedString
([String ("value: {x + 1}", (7,8--7,24))], Regular,
(7,7--7,24)), (7,4--7,5), Yes (7,0--7,24),
{ LeadingKeyword = Let (7,0--7,3)
InlineKeyword = None
EqualsRange = Some (7,6--7,7) })], (7,0--7,24));
Let
(false,
[SynBinding
(None, Normal, false, false, [],
PreXmlDoc ((8,0), FSharp.Compiler.Xml.XmlDocCollector),
SynValData
(None, SynValInfo ([], SynArgInfo ([], false, None)), None),
Named (SynIdent (y, None), false, None, (8,4--8,5)), None,
InterpolatedString
([String ("value: ", (8,8--8,18));
FillExpr
(App
(NonAtomic, false,
App
(NonAtomic, true,
LongIdent
(false,
SynLongIdent
([op_Addition], [],
[Some (OriginalNotation "+")]), None,
(8,20--8,21)), Ident x, (8,18--8,21)),
Const (Int32 1, (8,22--8,23)), (8,18--8,23)), None);
String ("", (8,23--8,25))], Regular, (8,8--8,25)),
(8,4--8,5), Yes (8,0--8,25), { LeadingKeyword = Let (8,0--8,3)
InlineKeyword = None
EqualsRange = Some (8,6--8,7) })],
(8,0--8,25))],
PreXmlDoc ((1,0), FSharp.Compiler.Xml.XmlDocCollector), [], None,
(1,0--8,25), { LeadingKeyword = Module (1,0--1,6) })], (true, true),
{ ConditionalDirectives = []
WarnDirectives = []
CodeComments = [] }, set []))
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Module

let f =$"""hello"""
let f = $"""hello"""
let g =$"""hello {name}"""
let g = $"""hello {name}"""
let y =$"""value: {x + 1}"""
let y = $"""value: {x + 1}"""
Loading
Loading