Skip to content
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

fix: disallow toplevel infix definitions for vals, vars, givens, methods and implicits #17994

Merged
merged 10 commits into from
Jul 13, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
case ClosureCannotHaveInternalParameterDependenciesID // errorNumber: 183
case MatchTypeNoCasesID // errorNumber: 184
case UnimportedAndImportedID // errorNumber: 185
case ToplevelDefCantBeInfixID // errorNumber: 186

def errorNumber = ordinal - 1

Expand Down
10 changes: 10 additions & 0 deletions compiler/src/dotty/tools/dotc/reporting/messages.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2938,3 +2938,13 @@ class ClosureCannotHaveInternalParameterDependencies(mt: Type)(using Context)
i"""cannot turn method type $mt into closure
|because it has internal parameter dependencies"""
def explain(using Context) = ""

class ToplevelDefCantBeInfix(sym: Symbol)(using Context)
extends SyntaxMsg(ToplevelDefCantBeInfixID):
def msg(using Context) = i"a toplevel $defName cannot be infix"
def explain(using Context) = ""
private val defName =
if sym.flags.is(Method) then "def"
else if sym.flags.is(Mutable) then "var"
else if sym.flags.is(Given) then "given"
else "val"
3 changes: 3 additions & 0 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,9 @@ object Checking {
fail(CannotHaveSameNameAs(sym, cls, CannotHaveSameNameAs.CannotBeOverridden))
sym.setFlag(Private) // break the overriding relationship by making sym Private
}

if sym.isWrappedToplevelDef && !sym.isType && sym.flags.is(Infix, butNot = Extension) then
fail(ToplevelDefCantBeInfix(sym))
checkApplicable(Erased,
!sym.isOneOf(MutableOrLazy, butNot = Given) && !sym.isType || sym.isClass)
checkCombination(Final, Open)
Expand Down
20 changes: 20 additions & 0 deletions tests/neg/i17738-toplevel-infix.check
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
-- [E186] Syntax Error: tests/neg/i17738-toplevel-infix.scala:13:10 ----------------------------------------------------
13 |infix val toplevelVal = ??? // error
| ^
| a toplevel val cannot be infix
-- [E186] Syntax Error: tests/neg/i17738-toplevel-infix.scala:14:10 ----------------------------------------------------
14 |infix var toplevelVar = ??? // error
| ^
| a toplevel var cannot be infix
-- [E186] Syntax Error: tests/neg/i17738-toplevel-infix.scala:15:10 ----------------------------------------------------
15 |infix def toplevelDef = ??? // error
| ^
| a toplevel def cannot be infix
-- [E186] Syntax Error: tests/neg/i17738-toplevel-infix.scala:16:12 ----------------------------------------------------
16 |infix given toplevelGiven: Int = ??? // error
| ^
| a toplevel given cannot be infix
-- [E186] Syntax Error: tests/neg/i17738-toplevel-infix.scala:17:19 ----------------------------------------------------
17 |infix implicit val topevelImplicit: Int = ??? // error
| ^
| a toplevel val cannot be infix
17 changes: 17 additions & 0 deletions tests/neg/i17738-toplevel-infix.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
infix type A[b, a] = Nothing

infix type B[b, a] = b match {
case Int => a
}

infix class C[A, B]
infix trait D[A, B]

extension (x: Boolean)
infix def or (y: => Boolean) = x || y

infix val toplevelVal = ??? // error
infix var toplevelVar = ??? // error
infix def toplevelDef = ??? // error
infix given toplevelGiven: Int = ??? // error
infix implicit val topevelImplicit: Int = ??? // error
mbovel marked this conversation as resolved.
Show resolved Hide resolved