diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 256940645ec3..e2ee528824cc 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -1818,6 +1818,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def termSymbol: Symbol = self.termSymbol def isSingleton: Boolean = self.isSingleton def memberType(member: Symbol): TypeRepr = + assert(self.derivesFrom(member.owner), s"$member is not a member of ${self.show}") member.info.asSeenFrom(self, member.owner) def baseClasses: List[Symbol] = self.baseClasses def baseType(cls: Symbol): TypeRepr = self.baseType(cls) diff --git a/scaladoc-testcases/src/tests/exports1.scala b/scaladoc-testcases/src/tests/exports.scala similarity index 82% rename from scaladoc-testcases/src/tests/exports1.scala rename to scaladoc-testcases/src/tests/exports.scala index f719bca35eb1..b5f8c9f8ef60 100644 --- a/scaladoc-testcases/src/tests/exports1.scala +++ b/scaladoc-testcases/src/tests/exports.scala @@ -1,5 +1,5 @@ package tests -package exports1 +package exports class A: //unexpected def aDefInt: Int @@ -21,7 +21,7 @@ class A: //unexpected = ??? def fn[T, U]: T => U = ??? - object Object //expected: val Obj: Object.type + object Object //expected: final val Obj: Object.type val x: HKT[List, Int] //expected: val x: A.this.HKT[List, Int] = ??? class Class(val a: Int, val b: Int) extends Serializable //expected: final type Class = a.Class @@ -42,4 +42,12 @@ object X: //unexpected var xVarInt: Int = 1 var xVar1: 1 - = 1 \ No newline at end of file + = 1 + +class B: //unexpected + val a: A + = new A + export a.{Object => Obj, _} + export X._ + def obj: Obj.type + = Obj diff --git a/scaladoc-testcases/src/tests/exports2.scala b/scaladoc-testcases/src/tests/exports2.scala deleted file mode 100644 index c6450265ab1b..000000000000 --- a/scaladoc-testcases/src/tests/exports2.scala +++ /dev/null @@ -1,12 +0,0 @@ -package tests -package exports2 - -import exports1._ - -class B: - val a: A - = new A - export a.{Object => Obj, _} - export X._ - def obj: Obj.type - = Obj diff --git a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala index 1598accf4f40..8d5fdf196b4a 100644 --- a/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala +++ b/scaladoc/src/dotty/tools/scaladoc/tasty/ClassLikeSupport.scala @@ -178,10 +178,10 @@ trait ClassLikeSupport: case rhs => rhs }.map(_.tpe.termSymbol).filter(_.exists).map(_.tree).map { case v: ValDef if v.symbol.flags.is(Flags.Module) && !v.symbol.flags.is(Flags.Synthetic) => - v.symbol.owner -> Symbol.newVal(c.symbol, dd.name, v.tpt.tpe, Flags.Final, Symbol.noSymbol).tree + v.symbol.owner -> Symbol.newVal(v.symbol.owner, dd.name, v.tpt.tpe, Flags.Final, Symbol.noSymbol).tree case other => other.symbol.owner -> other }.flatMap { (originalOwner, tree) => - parseMember(c)(tree) + parseMember(originalOwner.tree.asInstanceOf[ClassDef])(tree) .map { m => m .withDRI(dd.symbol.dri) .withName(dd.symbol.normalizedName) @@ -324,7 +324,7 @@ trait ClassLikeSupport: val enumVals = companion.membersToDocument.collect { case vd: ValDef if !isSyntheticField(vd.symbol) && vd.symbol.flags.is(Flags.Enum) && vd.symbol.flags.is(Flags.Case) => vd - }.toList.map(parseValDef(classDef, _)) + }.toList.map(parseValDef(companion, _)) val enumTypes = companion.membersToDocument.collect { case td: TypeDef if !td.symbol.flags.is(Flags.Synthetic) && td.symbol.flags.is(Flags.Enum) && td.symbol.flags.is(Flags.Case) => td diff --git a/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala b/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala index bdedc3f14ce0..2539a49fd625 100644 --- a/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala +++ b/scaladoc/test/dotty/tools/scaladoc/signatures/SignatureTest.scala @@ -31,9 +31,11 @@ abstract class SignatureTest( .map { file => Source.fromFile(s"${BuildInfo.test_testcasesSourceRoot}/tests/$file.scala") } .flatMap(signaturesFromSources(_, signatureKinds)) .toList + val expectedFromSources: Map[String, List[String]] = allSignaturesFromSources .collect { case e: Expected => e } .groupMap(_.name)(_.signature) + val unexpectedFromSources: Set[String] = allSignaturesFromSources.collect { case Unexpected(name) => name }.toSet val actualSignatures: Map[String, Seq[String]] = @@ -84,7 +86,7 @@ abstract class SignatureTest( private def findName(signature: String, kinds: Seq[String]): Option[String] = for - kindMatch <- kinds.flatMap(k =>s"\\b$k\\b".r.findFirstMatchIn(signature)).headOption + kindMatch <- kinds.flatMap(k => s"\\b$k\\b".r.findFirstMatchIn(signature)).minByOption(_.start) kind <- Option(kindMatch.group(0)) // to filter out nulls afterKind <- Option(kindMatch.after(0)) // to filter out nulls name <- if kind.contains("extension") then Some(signature) // The name of an extension will always be the signature itself @@ -98,7 +100,8 @@ abstract class SignatureTest( .toSeq .flatMap { case unexpectedRegex(signature) => findName(signature, kinds).map(Unexpected(_)) - case expectedRegex(signature) => findName(signature, kinds).map(Expected(_, signature)) + case expectedRegex(signature) => + findName(signature, kinds).map(Expected(_, signature)) case signature => findName(signature, kinds).map( Expected(_, commentRegex.replaceAllIn(signature, "") diff --git a/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala b/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala index 2b654d186aef..daea48499a81 100644 --- a/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala +++ b/scaladoc/test/dotty/tools/scaladoc/signatures/TranslatableSignaturesTestCases.scala @@ -93,7 +93,7 @@ class ContextBounds extends SignatureTest("contextBounds", SignatureTest.all) class FBoundedTypeParameters extends SignatureTest("fboundedTypeParameters", SignatureTest.all) -class Exports extends SignatureTest("exports2", SignatureTest.all, sourceFiles = List("exports1", "exports2")) +class Exports extends SignatureTest("exports", SignatureTest.all, filterFunc = _.toString.endsWith("B.html")) class ContextFunctions extends SignatureTest("contextfunctions", SignatureTest.all) diff --git a/tests/neg-macros/i15159/Macro_1.scala b/tests/neg-macros/i15159/Macro_1.scala new file mode 100644 index 000000000000..617478f51965 --- /dev/null +++ b/tests/neg-macros/i15159/Macro_1.scala @@ -0,0 +1,10 @@ +import scala.quoted.* +object TestMacro: + inline def test[T]: Unit = ${ testImpl[T] } + def testImpl[T: Type](using Quotes): Expr[Unit] = + import quotes.reflect.* + val tpe = TypeRepr.of[T] + tpe.typeSymbol.children.map { childSymbol => + tpe.memberType(childSymbol) // not a member of tpe + } + '{ () } diff --git a/tests/neg-macros/i15159/Test_2.scala b/tests/neg-macros/i15159/Test_2.scala new file mode 100644 index 000000000000..0c290822550e --- /dev/null +++ b/tests/neg-macros/i15159/Test_2.scala @@ -0,0 +1,6 @@ +sealed trait A +case class X(i: Int) extends A + +object Test extends App { + TestMacro.test[A] // error +} diff --git a/tests/run-macros/i13230/Macros_1.scala b/tests/run-macros/i13230/Macros_1.scala index 424358e83b1a..68d25d6be43a 100644 --- a/tests/run-macros/i13230/Macros_1.scala +++ b/tests/run-macros/i13230/Macros_1.scala @@ -7,6 +7,6 @@ inline def showEnumChildren = ${ showEnumChildrenExpr } def showEnumChildrenExpr(using Quotes) = import quotes.reflect.* - val repr = TypeRepr.of[E] + val repr = TypeRepr.of[E.type] // we know that all the implementations of the class E are in the object E Expr(TypeRepr.of[E].classSymbol.get.children.map(sym => (sym.name, repr.memberType(sym).show)))