diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index b06b01f801bc..c2c29f60ed92 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -558,7 +558,7 @@ object desugar { else if (originalTparams.isEmpty) appliedRef(enumClassRef) else { - ctx.error(i"explicit extends clause needed because both enum case and enum class have type parameters" + ctx.error(TypedCaseDoesNotExplicitlyExtendTypedEnum(enumClass, cdef) , cdef.sourcePos.startPos) appliedTypeTree(enumClassRef, constrTparams map (_ => anyRef)) } @@ -930,22 +930,27 @@ object desugar { def makeExtensionDef(mdef: Tree, tparams: List[TypeDef], leadingParams: List[ValDef], givenParamss: List[List[ValDef]])(using ctx: Context): Tree = { - val allowed = "allowed here, since collective parameters are given" mdef match { case mdef: DefDef => if (mdef.mods.is(Extension)) { - ctx.error(em"No extension method $allowed", mdef.sourcePos) + ctx.error(NoExtensionMethodAllowed(mdef), mdef.sourcePos) mdef + } else { + if (tparams.nonEmpty && mdef.tparams.nonEmpty) then + ctx.error(ExtensionMethodCannotHaveTypeParams(mdef), mdef.tparams.head.sourcePos) + mdef + else cpy.DefDef(mdef)( + tparams = tparams ++ mdef.tparams, + vparamss = leadingParams :: givenParamss ::: mdef.vparamss + ).withMods(mdef.mods | Extension) } - else cpy.DefDef(mdef)( - tparams = tparams ++ mdef.tparams, - vparamss = leadingParams :: givenParamss ::: mdef.vparamss - ).withMods(mdef.mods | Extension) case mdef: Import => mdef - case mdef => - ctx.error(em"Only methods $allowed", mdef.sourcePos) + case mdef if !mdef.isEmpty => { + ctx.error(ExtensionCanOnlyHaveDefs(mdef), mdef.sourcePos) mdef + } + case mdef => mdef } } @@ -979,7 +984,7 @@ object desugar { if (name.isEmpty) name = name.likeSpaced(inventGivenOrExtensionName(impl)) if (ctx.owner == defn.ScalaPackageClass && defn.reservedScalaClassNames.contains(name.toTypeName)) { def kind = if (name.isTypeName) "class" else "object" - ctx.error(em"illegal redefinition of standard $kind $name", mdef.sourcePos) + ctx.error(IllegalRedefinitionOfStandardKind(kind, name), mdef.sourcePos) name = name.errorName } name @@ -998,7 +1003,7 @@ object desugar { case Some(DefDef(name, _, (vparam :: _) :: _, _, _)) => s"extension_${name}_${inventTypeName(vparam.tpt)}" case _ => - ctx.error(i"anonymous instance must implement a type or have at least one extension method", impl.sourcePos) + ctx.error(AnonymousInstanceCannotBeEmpty(impl), impl.sourcePos) nme.ERROR.toString else impl.parents.map(inventTypeName(_)).mkString("given_", "_", "") @@ -1170,10 +1175,9 @@ object desugar { def checkModifiers(tree: Tree)(implicit ctx: Context): Tree = tree match { case tree: MemberDef => var tested: MemberDef = tree - def fail(msg: String) = ctx.error(msg, tree.sourcePos) def checkApplicable(flag: Flag, test: MemberDefTest): Unit = if (tested.mods.is(flag) && !test.applyOrElse(tree, (md: MemberDef) => false)) { - fail(i"modifier `${flag.flagsString}` is not allowed for this definition") + ctx.error(ModifierNotAllowedForDefinition(flag), tree.sourcePos) tested = tested.withMods(tested.mods.withoutFlags(flag)) } checkApplicable(Opaque, legalOpaque) @@ -1795,7 +1799,7 @@ object desugar { def traverse(tree: untpd.Tree)(implicit ctx: Context): Unit = tree match { case Splice(expr) => collect(expr) case TypSplice(expr) => - ctx.error("Type splices cannot be used in val patterns. Consider using `match` instead.", tree.sourcePos) + ctx.error(TypeSpliceInValPattern(expr), tree.sourcePos) case _ => traverseChildren(tree) } }.traverse(expr) diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index afc4377e8d25..08c5aa87b10c 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -3470,17 +3470,6 @@ object Parsers { Template(constr, parents, Nil, EmptyValDef, Nil) } - def checkExtensionMethod(tparams: List[Tree], stat: Tree): Unit = stat match { - case stat: DefDef => - if stat.mods.is(Extension) then - syntaxError(i"no extension method allowed here since leading parameter was already given", stat.span) - else if tparams.nonEmpty && stat.tparams.nonEmpty then - syntaxError(i"extension method cannot have type parameters since some were already given previously", - stat.tparams.head.span) - case stat => - syntaxError(i"extension clause can only define methods", stat.span) - } - /** GivenDef ::= [GivenSig] [‘_’ ‘<:’] Type ‘=’ Expr * | [GivenSig] ConstrApps [TemplateBody] * GivenSig ::= [id] [DefTypeParamClause] {UsingParamClauses} ‘as’ @@ -3541,7 +3530,6 @@ object Parsers { possibleTemplateStart() if !in.isNestedStart then syntaxError("Extension without extension methods") val templ = templateBodyOpt(makeConstructor(tparams, extParams :: givenParamss), Nil, Nil) - templ.body.foreach(checkExtensionMethod(tparams, _)) val edef = ModuleDef(name, templ) finalizeDef(edef, addFlag(mods, Given), start) } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala index b35d041d7c47..d079e0ce14c1 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/ErrorMessageID.scala @@ -155,7 +155,16 @@ enum ErrorMessageID extends java.lang.Enum[ErrorMessageID] { CaseClassMissingNonImplicitParamListID, EnumerationsShouldNotBeEmptyID, AbstractCannotBeUsedForObjectsID, - ModifierRedundantForObjectsID + ModifierRedundantForObjectsID, + TypedCaseDoesNotExplicitlyExtendTypedEnumID, + IllegalRedefinitionOfStandardKindID, + NoExtensionMethodAllowedID, + ExtensionMethodCannotHaveTypeParamsID, + ExtensionCanOnlyHaveDefsID, + UnexpectedPatternForSummonFromID, + AnonymousInstanceCannotBeEmptyID, + TypeSpliceInValPatternID, + ModifierNotAllowedForDefinitionID def errorNumber = ordinal - 2 } diff --git a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala index f3f27fbd1ffe..648cf17c654b 100644 --- a/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/diagnostic/messages.scala @@ -2443,4 +2443,117 @@ object messages { | ${hl("object")} ${mdef.name} { } |""".stripMargin } + + case class TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef: Symbol, caseDef: untpd.TypeDef)(implicit ctx: Context) + extends Message(TypedCaseDoesNotExplicitlyExtendTypedEnumID) { + val kind: String = "Syntax" + val msg: String = i"explicit extends clause needed because both enum case and enum class have type parameters" + + val explanation: String = + em"""Enumerations where the enum class as well as the enum case have type parameters need + |an explicit extends. + |for example: + | ${hl("enum")} ${enumDef.name}[T] { + | ${hl("case")} ${caseDef.name}[U](u: U) ${hl("extends")} ${enumDef.name}[U] + | } + |""".stripMargin + } + + case class IllegalRedefinitionOfStandardKind(kindType: String, name: Name)(implicit ctx: Context) + extends Message(IllegalRedefinitionOfStandardKindID) { + val kind: String = "Syntax" + val msg: String = em"illegal redefinition of standard $kindType $name" + + val explanation: String = + em"""| "$name" is a standard Scala core `$kindType` + | Please choose a different name to avoid conflicts + |""".stripMargin + } + + case class NoExtensionMethodAllowed(mdef: untpd.DefDef)(implicit ctx: Context) + extends Message(NoExtensionMethodAllowedID) { + val kind: String = "Syntax" + val msg: String = em"No extension method allowed here, since collective parameters are given" + + val explanation: String = + em"""|Extension method: + | `${mdef}` + |is defined inside an extension clause which has collective parameters. + |""".stripMargin + } + + case class ExtensionMethodCannotHaveTypeParams(mdef: untpd.DefDef)(implicit ctx: Context) + extends Message(ExtensionMethodCannotHaveTypeParamsID) { + val kind: String = "Syntax" + val msg: String = i"Extension method cannot have type parameters since some were already given previously" + + val explanation: String = + em"""|Extension method: + | `${mdef}` + |has type parameters `[${mdef.tparams.map(_.show).mkString(",")}]`, while the extension clause has + |it's own type parameters. Please consider moving these to the extension clause's type parameter list. + |""".stripMargin + } + + case class ExtensionCanOnlyHaveDefs(mdef: untpd.Tree)(implicit ctx: Context) + extends Message(ExtensionCanOnlyHaveDefsID) { + val kind: String = "Syntax" + val msg: String = em"Only methods allowed here, since collective parameters are given" + + val explanation: String = + em"""Extension clauses can only have `def`s + | `${mdef.show}` is not a valid expression here. + |""".stripMargin + } + + case class UnexpectedPatternForSummonFrom(tree: Tree[_])(implicit ctx: Context) + extends Message(UnexpectedPatternForSummonFromID) { + val kind: String = "Syntax" + val msg: String = em"Unexpected pattern for summonFrom. Expected ${hl("`x: T`")} or ${hl("`_`")}" + + val explanation: String = + em"""|The pattern "${tree.show}" provided in the ${hl("case")} expression of the ${hl("summonFrom")}, + | needs to be of the form ${hl("`x: T`")} or ${hl("`_`")}. + | + | Example usage: + | inline def a = summonFrom { + | case x: T => ??? + | } + | + | or + | inline def a = summonFrom { + | case _ => ??? + | } + |""".stripMargin + } + + case class AnonymousInstanceCannotBeEmpty(impl: untpd.Template)(implicit ctx: Context) + extends Message(AnonymousInstanceCannotBeEmptyID) { + val kind: String = "Syntax" + val msg: String = i"anonymous instance must implement a type or have at least one extension method" + + val explanation: String = + em"""|Anonymous instances cannot be defined with an empty body. The block + |`${impl.show}` should either contain an implemented type or at least one extension method. + |""".stripMargin + } + + case class TypeSpliceInValPattern(expr: untpd.Tree)(implicit ctx: Context) + extends Message(TypeSpliceInValPatternID) { + val kind: String = "Syntax" + val msg: String = "Type splices cannot be used in val patterns. Consider using `match` instead." + + val explanation: String = + em"""|Type splice: `$$${expr.show}` cannot be used in a `val` pattern. Consider rewriting the `val` pattern + |as a `match` with a corresponding `case` to replace the `val`. + |""".stripMargin + } + + case class ModifierNotAllowedForDefinition(flag: Flag)(implicit ctx: Context) + extends Message(ModifierNotAllowedForDefinitionID) { + val kind: String = "Syntax" + val msg: String = s"Modifier `${flag.flagsString}` is not allowed for this definition" + + val explanation: String = "" + } } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index cd4079bf5b56..92d19d12a78b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -28,7 +28,8 @@ import collection.mutable import config.Printers.{overload, typr, unapp} import TypeApplications._ -import reporting.diagnostic.{Message, messages} +import reporting.diagnostic.Message +import reporting.diagnostic.messages.{UnexpectedPatternForSummonFrom, NotAMember} import reporting.trace import Constants.{Constant, IntTag, LongTag} import dotty.tools.dotc.reporting.diagnostic.messages.{UnapplyInvalidReturnType, NotAnExtractor, UnapplyInvalidNumberOfArguments} @@ -916,7 +917,7 @@ trait Applications extends Compatibility { case CaseDef(Bind(_, Typed(_: Ident, _)), _, _) => // OK case CaseDef(Ident(name), _, _) if name == nme.WILDCARD => // Ok case CaseDef(pat, _, _) => - ctx.error("Unexpected pattern for summonFrom. Expected `x: T` or `_`", pat.sourcePos) + ctx.error(UnexpectedPatternForSummonFrom(pat), pat.sourcePos) } typed(untpd.InlineMatch(EmptyTree, cases).withSpan(arg.span), pt) case _ => @@ -1075,7 +1076,7 @@ trait Applications extends Compatibility { msgs match case msg :: Nil => msg.contained match - case messages.NotAMember(_, nme.unapply, _, _) => return notAnExtractor(tree) + case NotAMember(_, nme.unapply, _, _) => return notAnExtractor(tree) case _ => case _ => msgs.foreach(ctx.reporter.report) diff --git a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala index ebf967ce9b96..9dee80d55271 100644 --- a/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala +++ b/compiler/test/dotty/tools/dotc/reporting/ErrorMessagesTests.scala @@ -1770,4 +1770,177 @@ class ErrorMessagesTests extends ErrorMessagesTest { assertEquals("sealed modifier is redundant for objects", errorMsg) assertEquals("Foo", mdef.name.toString) } + + @Test def enumAndCaseWithTypesNeedExplicitExtends = + checkMessagesAfter(RefChecks.name) { + """ + |enum E[T,U,V] { + | case C[X,Y,Z](x: X, y: Y, z: Z) + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val TypedCaseDoesNotExplicitlyExtendTypedEnum(enumDef, caseDef) :: Nil = messages + assertEquals("explicit extends clause needed because both enum case and enum class have type parameters", errorMsg) + assertEquals("E", enumDef.name.toString) + assertEquals("C", caseDef.name.toString) + } + + @Test def illegalRedefinitionOfStandardKind = + checkMessagesAfter(RefChecks.name) { + """ package scala { + | class Any() + | } + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val IllegalRedefinitionOfStandardKind(kind, name) :: Nil = messages + assertEquals("illegal redefinition of standard class Any", errorMsg) + assertEquals("class", kind) + assertEquals("Any", name.toString) + } + + @Test def unexpectedPatternForSummonFrom = + checkMessagesAfter(RefChecks.name) { + """import compiletime.summonFrom + |inline def a = summonFrom { + | case x => ??? + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val UnexpectedPatternForSummonFrom(x) :: Nil = messages + assertEquals("Unexpected pattern for summonFrom. Expected `x: T` or `_`", errorMsg) + assertEquals("x", x.show) + } + + @Test def unexpectedPatternForSummonWithPatternBinder = + checkMessagesAfter(RefChecks.name) { + """import compiletime.summonFrom + |inline def a = summonFrom { + | case x@String => ??? + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val UnexpectedPatternForSummonFrom(x) :: Nil = messages + assertEquals("Unexpected pattern for summonFrom. Expected `x: T` or `_`", errorMsg) + assertEquals("given x @ String", x.show) + } + + @Test def extensionMethodsNotAllowed = + checkMessagesAfter(RefChecks.name) { + """object Test { + | extension on[T] (t: T) { + | def (c: T).f: T = ??? + | } + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val NoExtensionMethodAllowed(x) :: Nil = messages + assertEquals("No extension method allowed here, since collective parameters are given", errorMsg) + assertEquals("def (c: T) f: T = ???", x.show) + } + + @Test def extensionMethodTypeParamsNotAllowed = + checkMessagesAfter(RefChecks.name) { + """object Test { + | extension on[T] (t: T) { + | def f[U](u: U): T = ??? + | } + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val ExtensionMethodCannotHaveTypeParams(x) :: Nil = messages + assertEquals("Extension method cannot have type parameters since some were already given previously", errorMsg) + assertEquals("def f[U](u: U): T = ???", x.show) + } + + @Test def extensionMethodCanOnlyHaveDefs = + checkMessagesAfter(RefChecks.name) { + """object Test { + | extension on[T] (t: T) { + | val v: T = t + | } + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val ExtensionCanOnlyHaveDefs(x) :: Nil = messages + assertEquals("Only methods allowed here, since collective parameters are given", errorMsg) + assertEquals("val v: T = t", x.show) + } + + @Test def anonymousInstanceMustImplementAType = + checkMessagesAfter(RefChecks.name) { + """object Test { + | extension on[T] (t: T) { } + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + assertEquals("anonymous instance must implement a type or have at least one extension method", errorMsg) + } + + @Test def typeSplicesInValPatterns = + checkMessagesAfter(RefChecks.name) { + s"""import scala.quoted._ + |object Foo { + | def f(using q: QuoteContext) = { + | val t: Type[Int] = ??? + | val '[ *:[$$t] ] = ??? + | } + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val TypeSpliceInValPattern(x) :: Nil = messages + assertEquals("Type splices cannot be used in val patterns. Consider using `match` instead.", errorMsg) + assertEquals("t", x.show) + } + + @Test def modifierNotAllowedForDefinition = + checkMessagesAfter(RefChecks.name) { + """object Test { + | opaque def o: Int = 3 + |} + """.stripMargin + } + .expect { (ictx, messages) ⇒ + implicit val ctx: Context = ictx + assertMessageCount(1, messages) + val errorMsg = messages.head.msg + val ModifierNotAllowedForDefinition(x) :: Nil = messages + assertEquals("Modifier `opaque` is not allowed for this definition", errorMsg) + assertEquals("opaque", x.flagsString) + } } diff --git a/tests/neg/SummonFrom.check b/tests/neg/SummonFrom.check new file mode 100644 index 000000000000..e8bb4ad521f5 --- /dev/null +++ b/tests/neg/SummonFrom.check @@ -0,0 +1,12 @@ +-- [E153] Syntax Error: tests/neg/SummonFrom.scala:4:7 ----------------------------------------------------------------- +4 | case x => ??? // error + | ^ + | Unexpected pattern for summonFrom. Expected `x: T` or `_` + +longer explanation available when compiling with `-explain` +-- [E153] Syntax Error: tests/neg/SummonFrom.scala:8:7 ----------------------------------------------------------------- +8 | case x@String => ??? // error + | ^^^^^^^^ + | Unexpected pattern for summonFrom. Expected `x: T` or `_` + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/SummonFrom.scala b/tests/neg/SummonFrom.scala new file mode 100644 index 000000000000..79cde30ab1dc --- /dev/null +++ b/tests/neg/SummonFrom.scala @@ -0,0 +1,9 @@ +import compiletime.summonFrom + +inline def a = summonFrom { + case x => ??? // error +} + +inline def b = summonFrom { + case x@String => ??? // error +} \ No newline at end of file diff --git a/tests/neg/anonymous-instance-cannot-be-empty.check b/tests/neg/anonymous-instance-cannot-be-empty.check new file mode 100644 index 000000000000..f6b50962ebc4 --- /dev/null +++ b/tests/neg/anonymous-instance-cannot-be-empty.check @@ -0,0 +1,6 @@ +-- [E154] Syntax Error: tests/neg/anonymous-instance-cannot-be-empty.scala:2:15 ---------------------------------------- +2 | extension on[T] (t: T) { } // error + | ^^^^^^^^ + | anonymous instance must implement a type or have at least one extension method + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/anonymous-instance-cannot-be-empty.scala b/tests/neg/anonymous-instance-cannot-be-empty.scala new file mode 100644 index 000000000000..3581b17ebe88 --- /dev/null +++ b/tests/neg/anonymous-instance-cannot-be-empty.scala @@ -0,0 +1,3 @@ +object Test { + extension on[T] (t: T) { } // error +} \ No newline at end of file diff --git a/tests/neg/enumWithType.check b/tests/neg/enumWithType.check new file mode 100644 index 000000000000..fcc06d3532a4 --- /dev/null +++ b/tests/neg/enumWithType.check @@ -0,0 +1,6 @@ +-- [E148] Syntax Error: tests/neg/enumWithType.scala:2:2 --------------------------------------------------------------- +2 | case C[U](u: U) // error + | ^ + | explicit extends clause needed because both enum case and enum class have type parameters + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/enumWithType.scala b/tests/neg/enumWithType.scala new file mode 100644 index 000000000000..25b2940d511e --- /dev/null +++ b/tests/neg/enumWithType.scala @@ -0,0 +1,3 @@ +enum E[T] { + case C[U](u: U) // error +} \ No newline at end of file diff --git a/tests/neg/extension-cannot-have-type.check b/tests/neg/extension-cannot-have-type.check new file mode 100644 index 000000000000..b98355683c05 --- /dev/null +++ b/tests/neg/extension-cannot-have-type.check @@ -0,0 +1,6 @@ +-- [E151] Syntax Error: tests/neg/extension-cannot-have-type.scala:3:10 ------------------------------------------------ +3 | def f[U](u: U): T = ??? // error : extension method cannot have type params + | ^ + | Extension method cannot have type parameters since some were already given previously + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/extension-cannot-have-type.scala b/tests/neg/extension-cannot-have-type.scala new file mode 100644 index 000000000000..67470fe13f0f --- /dev/null +++ b/tests/neg/extension-cannot-have-type.scala @@ -0,0 +1,5 @@ +object Test { + extension on[T] (t: T) { + def f[U](u: U): T = ??? // error : extension method cannot have type params + } +} \ No newline at end of file diff --git a/tests/neg/extension-method-not-allowed.check b/tests/neg/extension-method-not-allowed.check new file mode 100644 index 000000000000..fd109a3e921d --- /dev/null +++ b/tests/neg/extension-method-not-allowed.check @@ -0,0 +1,6 @@ +-- [E150] Syntax Error: tests/neg/extension-method-not-allowed.scala:3:8 ----------------------------------------------- +3 | def (c: T).f: T = ??? // error : No extension method allowed here + | ^^^^^^^^^^^^^^^^^^^^^ + | No extension method allowed here, since collective parameters are given + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/extension-method-not-allowed.scala b/tests/neg/extension-method-not-allowed.scala new file mode 100644 index 000000000000..a50235481c22 --- /dev/null +++ b/tests/neg/extension-method-not-allowed.scala @@ -0,0 +1,5 @@ +object Test { + extension on[T] (t: T) { + def (c: T).f: T = ??? // error : No extension method allowed here + } +} \ No newline at end of file diff --git a/tests/neg/extensions-can-only-have-defs.check b/tests/neg/extensions-can-only-have-defs.check new file mode 100644 index 000000000000..7fd29b92aba8 --- /dev/null +++ b/tests/neg/extensions-can-only-have-defs.check @@ -0,0 +1,6 @@ +-- [E152] Syntax Error: tests/neg/extensions-can-only-have-defs.scala:3:8 ---------------------------------------------- +3 | val v: T = ??? // error : extensions can only have defs + | ^^^^^^^^^^^^^^ + | Only methods allowed here, since collective parameters are given + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/extensions-can-only-have-defs.scala b/tests/neg/extensions-can-only-have-defs.scala new file mode 100644 index 000000000000..225d065e66f7 --- /dev/null +++ b/tests/neg/extensions-can-only-have-defs.scala @@ -0,0 +1,5 @@ +object Test { + extension on[T] (t: T) { + val v: T = ??? // error : extensions can only have defs + } +} \ No newline at end of file diff --git a/tests/neg/i6900.scala b/tests/neg/i6900.scala index c9ead6a99051..a81b4ba58350 100644 --- a/tests/neg/i6900.scala +++ b/tests/neg/i6900.scala @@ -4,12 +4,12 @@ object Test2 { extension on [A](a: A): def foo[C]: C => A = _ => a // error: extension method cannot have type parameters - 1.foo.foo + 1.foo.foo // error: foo is undefined // ... but have to pass 2 parameters - 1.foo.foo[Any => Int, String] - 1.foo[Int, String].foo - 1.foo[Int, String].foo[String => Int, String] + 1.foo.foo[Any => Int, String] // error: foo is undefined + 1.foo[Int, String].foo // error: foo is undefined + 1.foo[Int, String].foo[String => Int, String] // error: foo is undefined } diff --git a/tests/neg/modifier-not-allowed.check b/tests/neg/modifier-not-allowed.check new file mode 100644 index 000000000000..f80ffb85495b --- /dev/null +++ b/tests/neg/modifier-not-allowed.check @@ -0,0 +1,4 @@ +-- [E156] Syntax Error: tests/neg/modifier-not-allowed.scala:2:13 ------------------------------------------------------ +2 | opaque def o: Int = 3 // error + | ^^^^^^^^^^^^^^^^^^^^^ + | Modifier `opaque` is not allowed for this definition diff --git a/tests/neg/modifier-not-allowed.scala b/tests/neg/modifier-not-allowed.scala new file mode 100644 index 000000000000..2838dbb8f3eb --- /dev/null +++ b/tests/neg/modifier-not-allowed.scala @@ -0,0 +1,3 @@ +object Test { + opaque def o: Int = 3 // error +} \ No newline at end of file diff --git a/tests/neg/scalaStandardRedefinition.check b/tests/neg/scalaStandardRedefinition.check new file mode 100644 index 000000000000..ca31f76ff523 --- /dev/null +++ b/tests/neg/scalaStandardRedefinition.check @@ -0,0 +1,6 @@ +-- [E149] Syntax Error: tests/neg/scalaStandardRedefinition.scala:2:8 -------------------------------------------------- +2 | class Any() // error + | ^^^^^^^^^^^ + | illegal redefinition of standard class Any + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/scalaStandardRedefinition.scala b/tests/neg/scalaStandardRedefinition.scala new file mode 100644 index 000000000000..92f026f9b477 --- /dev/null +++ b/tests/neg/scalaStandardRedefinition.scala @@ -0,0 +1,3 @@ +package scala { + class Any() // error +} \ No newline at end of file diff --git a/tests/neg/type-splice-in-val-pattern.check b/tests/neg/type-splice-in-val-pattern.check new file mode 100644 index 000000000000..1ccc67e8ec40 --- /dev/null +++ b/tests/neg/type-splice-in-val-pattern.check @@ -0,0 +1,6 @@ +-- [E155] Syntax Error: tests/neg/type-splice-in-val-pattern.scala:5:14 ------------------------------------------------ +5 | val '[ *:[$t] ] = ??? // error + | ^^ + | Type splices cannot be used in val patterns. Consider using `match` instead. + +longer explanation available when compiling with `-explain` diff --git a/tests/neg/type-splice-in-val-pattern.scala b/tests/neg/type-splice-in-val-pattern.scala new file mode 100644 index 000000000000..ba4a3d1d04ba --- /dev/null +++ b/tests/neg/type-splice-in-val-pattern.scala @@ -0,0 +1,7 @@ +import scala.quoted._ +object Foo { + def f(using q: QuoteContext) = { + val t: Type[Int] = ??? + val '[ *:[$t] ] = ??? // error + } +} \ No newline at end of file