Repository: scalameta/scalameta (scala)

Issue:
InvariantFailedException when attempting to extend a type
Version `4.5.4`:

```scala
trait B extends A.type
```
results in an `org.scalameta.invariants.InvariantFailedException`:
<details>

```
Exception in thread "main" org.scalameta.invariants.InvariantFailedException: invariant failed:
when verifying scala.meta.internal.trees.`package`.XtensionTreesType(tpe).isConstructable
found that scala.meta.internal.trees.`package`.XtensionTreesType(tpe).isConstructable is false
where tpe = A.type
	at org.scalameta.invariants.InvariantFailedException$.raise(Exceptions.scala:19)
	at scala.meta.Init$.internal$265(Trees.scala:494)
	at scala.meta.Init$.apply(Trees.scala:493)
	at scala.meta.internal.parsers.ScalametaParser.$anonfun$initRest$1(ScalametaParser.scala:3834)
	at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:296)
	at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:337)
	at scala.meta.internal.parsers.ScalametaParser.initRest(ScalametaParser.scala:3812)
	at scala.meta.internal.parsers.ScalametaParser.initInsideTemplate(ScalametaParser.scala:3800)
	at scala.meta.internal.parsers.ScalametaParser.init(ScalametaParser.scala:3891)
	at scala.meta.internal.parsers.ScalametaParser.templateParents(ScalametaParser.scala:3901)
	at scala.meta.internal.parsers.ScalametaParser.$anonfun$template$1(ScalametaParser.scala:3949)
	at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:296)
	at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:337)
	at scala.meta.internal.parsers.ScalametaParser.template(ScalametaParser.scala:3937)
	at scala.meta.internal.parsers.ScalametaParser.$anonfun$templateOpt$1(ScalametaParser.scala:3980)
	at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:296)
	at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:337)
	at scala.meta.internal.parsers.ScalametaParser.templateOpt(ScalametaParser.scala:3969)
	at scala.meta.internal.parsers.ScalametaParser.$anonfun$traitDef$1(ScalametaParser.scala:3617)
	at scala.meta.internal.parsers.ScalametaParser.autoEndPos(ScalametaParser.scala:339)
	at scala.meta.internal.parsers.ScalametaParser.autoEndPos(ScalametaParser.scala:341)
	at scala.meta.internal.parsers.ScalametaParser.traitDef(ScalametaParser.scala:3596)
	at scala.meta.internal.parsers.ScalametaParser.tmplDef(ScalametaParser.scala:3576)
	at scala.meta.internal.parsers.ScalametaParser.topLevelTmplDef(ScalametaParser.scala:3565)
	at scala.meta.internal.parsers.ScalametaParser$$anonfun$4.applyOrElse(ScalametaParser.scala:4140)
	at scala.meta.internal.parsers.ScalametaParser$$anonfun$4.applyOrElse(ScalametaParser.scala:4128)
	at scala.PartialFunction.$anonfun$runWith$1(PartialFunction.scala:231)
	at scala.PartialFunction.$anonfun$runWith$1$adapted(PartialFunction.scala:230)
	at scala.meta.internal.parsers.ScalametaParser.statSeqBuf(ScalametaParser.scala:4121)
	at scala.meta.internal.parsers.ScalametaParser.$anonfun$batchSource$14(ScalametaParser.scala:4337)
	at scala.Option.getOrElse(Option.scala:201)
	at scala.meta.internal.parsers.ScalametaParser.$anonfun$batchSource$1(ScalametaParser.scala:4337)
	at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:296)
	at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:337)
	at scala.meta.internal.parsers.ScalametaParser.batchSource(ScalametaParser.scala:4292)
	at scala.meta.internal.parsers.ScalametaParser.$anonfun$source$1(ScalametaParser.scala:4285)
	at scala.meta.internal.parsers.ScalametaParser.atPos(ScalametaParser.scala:296)
	at scala.meta.internal.parsers.ScalametaParser.autoPos(ScalametaParser.scala:337)
	at scala.meta.internal.parsers.ScalametaParser.source(ScalametaParser.scala:4285)
	at scala.meta.internal.parsers.ScalametaParser.entrypointSource(ScalametaParser.scala:4290)
	at scala.meta.internal.parsers.ScalametaParser.parseSourceImpl(ScalametaParser.scala:132)
	at scala.meta.internal.parsers.ScalametaParser.$anonfun$parseSource$1(ScalametaParser.scala:129)
	at scala.meta.internal.parsers.ScalametaParser.parseRuleAfterBOF(ScalametaParser.scala:56)
	at scala.meta.internal.parsers.ScalametaParser.parseRule(ScalametaParser.scala:51)
	at scala.meta.internal.parsers.ScalametaParser.parseSource(ScalametaParser.scala:129)
	at scala.meta.parsers.Parse$.$anonfun$parseSource$1(Parse.scala:29)
	at scala.meta.parsers.Parse$$anon$1.apply(Parse.scala:36)
	at scala.meta.parsers.Api$XtensionParseDialectInput.parse(Api.scala:25)
	at scala.meta.parsers.Api$XtensionParseInputLike.parse(Api.scala:14)
	at a$.delayedEndpoint$a$1(a.scala:5)
	at a$delayedInit$body.apply(a.scala:1)
	at scala.Function0.apply$mcV$sp(Function0.scala:39)
	at scala.Function0.apply$mcV$sp$(Function0.scala:39)
	at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:17)
	at scala.App.$anonfun$main$1(App.scala:76)
	at scala.App.$anonfun$main$1$adapted(App.scala:76)
	at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:563)
	at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:561)
	at scala.collection.AbstractIterable.foreach(Iterable.scala:926)
	at scala.App.main(App.scala:76)
	at scala.App.main$(App.scala:74)
	at a$.main(a.scala:1)
	at a.main(a.scala)
```

</details>

[Scastie](https://scastie.scala-lang.org/h0q06oYrRxiKE8mLdTNrCg)

Pull request:
Fixes https://github.com/scalameta/scalameta/issues/2741

Patch:
diff --git a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
index b71f5c3579..8c7df16851 100644
--- a/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
+++ b/scalameta/parsers/shared/src/main/scala/scala/meta/internal/parsers/ScalametaParser.scala
@@ -3358,7 +3358,9 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
 
     def parents() = {
       val parents = ListBuffer[Init](
-        autoEndPos(decltype)(initRest(decltype, allowArgss = true, allowBraces = false))
+        autoEndPos(decltype)(
+          initRest(decltype, allowArgss = true, allowBraces = false, allowTypeSingleton = false)
+        )
       )
       while (token.is[KwWith] && tryAhead[Ident]) parents += init()
       parents.toList
@@ -3777,15 +3779,20 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
       val t = autoPos(Term.This(autoPos { accept[KwThis]; Name.Anonymous() }))
       copyPos(t)(Type.Singleton(t))
     }
-    initRest(tpe, allowArgss = true, allowBraces = true)
+    initRest(tpe, allowArgss = true, allowBraces = true, allowTypeSingleton = true)
   }
 
   def initInsideAnnotation(allowArgss: Boolean): Init = {
-    initRest(exprSimpleType(), allowArgss = allowArgss, allowBraces = false)
+    initRest(
+      exprSimpleType(),
+      allowArgss = allowArgss,
+      allowBraces = false,
+      allowTypeSingleton = true
+    )
   }
 
   def initInsideTemplate(): Init = {
-    initRest(startModType(), allowArgss = true, allowBraces = false)
+    initRest(startModType(), allowArgss = true, allowBraces = false, allowTypeSingleton = false)
   }
 
   def quasiquoteInit(): Init = entrypointInit()
@@ -3797,7 +3804,12 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
     }
   }
 
-  def initRest(typeParser: => Type, allowArgss: Boolean, allowBraces: Boolean): Init = autoPos {
+  def initRest(
+      typeParser: => Type,
+      allowArgss: Boolean,
+      allowBraces: Boolean,
+      allowTypeSingleton: Boolean
+  ): Init = autoPos {
     def isPendingArglist = token.is[LeftParen] || (token.is[LeftBrace] && allowBraces)
     def newlineOpt() = {
       if (dialect.allowSignificantIndentation)
@@ -3809,6 +3821,8 @@ class ScalametaParser(input: Input)(implicit dialect: Dialect) { parser =>
         unquote[Init](t)
       case _ =>
         val tpe = typeParser
+        if (!allowTypeSingleton && tpe.is[Type.Singleton])
+          syntaxError(s"class type required but ${tpe.toString()} found", at = tpe.pos)
         val name = autoPos(Name.Anonymous())
         val argss = mutable.ListBuffer[List[Term]]()
         @inline def body() = {


Test patch:
diff --git a/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala b/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala
index 3222a51d7b..3bebb3fb57 100644
--- a/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala
+++ b/tests/shared/src/test/scala/scala/meta/tests/parsers/TemplateSuite.scala
@@ -337,4 +337,12 @@ class TemplateSuite extends ParseSuite {
     ) =
       templStat("object A { self: B => }")
   }
+
+  test("trait B extends A.type") {
+    val err = intercept[ParseException] {
+      templStat("trait B extends A.type")
+    }
+    assertNoDiff(err.shortMessage, "class type required but A.type found")
+  }
+
 }