From b0556ee3c2cdf5182ec4318dacf6864fa26b0906 Mon Sep 17 00:00:00 2001 From: Dale Wijnand Date: Fri, 11 Feb 2022 18:12:16 +0000 Subject: [PATCH 1/2] Fix backend assertion when using an exported enum An exported enum is a final method of the enum object. When selecting an inner enum case from it, that method will be the prefix. The method doesn't have a type symbol, we have to widen to method type and reach for its result type before we can get a handle on the type symbol to key off of. I wonder whether this widening and going to the result type is something that should happen during Erasure's denotation transformation though... Co-authored-by: Seth Tisue --- .../tools/backend/jvm/BCodeBodyBuilder.scala | 2 +- tests/pos/i13490.scala | 17 +++++++++++++++++ tests/run/i13490.min.scala | 13 +++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 tests/pos/i13490.scala create mode 100644 tests/run/i13490.min.scala diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala index 96ae4e8a00af..6516d32b6518 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala @@ -390,7 +390,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { def genLoadQualUnlessElidable(): Unit = { if (!qualSafeToElide) { genLoadQualifier(tree) } } // receiverClass is used in the bytecode to access the field. using sym.owner may lead to IllegalAccessError - def receiverClass = qualifier.tpe.typeSymbol + def receiverClass = qualifier.tpe.widenTermRefExpr.finalResultType.typeSymbol if (sym.is(Module)) { genLoadQualUnlessElidable() genLoadModule(tree) diff --git a/tests/pos/i13490.scala b/tests/pos/i13490.scala new file mode 100644 index 000000000000..c8f3213e0649 --- /dev/null +++ b/tests/pos/i13490.scala @@ -0,0 +1,17 @@ +object MyApi { + enum MyEnum(a: Int) { + case A extends MyEnum(1) + } + case class Foo(a: MyEnum) +} + +object Test { + export MyApi.* + import MyEnum.* + Foo(MyEnum.A) match { + case Foo(a) => + a match { + case A => + } + } +} diff --git a/tests/run/i13490.min.scala b/tests/run/i13490.min.scala new file mode 100644 index 000000000000..4f9c19764a5d --- /dev/null +++ b/tests/run/i13490.min.scala @@ -0,0 +1,13 @@ +object MyTypes: + enum MyEnum: + case Foo + case Bar + +object MyApi: + export MyTypes.* + +object MyUse: + import MyApi.MyEnum.Foo + def foo = Foo + +@main def Test = assert(MyUse.foo.toString == "Foo") From 64c04d5ecbd25d51a54dd33f7ba61ae904a00f5d Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Sat, 12 Feb 2022 19:52:59 +0100 Subject: [PATCH 2/2] Alternative fix based on tpd.desugarIdent --- compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala | 2 +- compiler/src/dotty/tools/dotc/ast/tpd.scala | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala index 6516d32b6518..96ae4e8a00af 100644 --- a/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala +++ b/compiler/src/dotty/tools/backend/jvm/BCodeBodyBuilder.scala @@ -390,7 +390,7 @@ trait BCodeBodyBuilder extends BCodeSkelBuilder { def genLoadQualUnlessElidable(): Unit = { if (!qualSafeToElide) { genLoadQualifier(tree) } } // receiverClass is used in the bytecode to access the field. using sym.owner may lead to IllegalAccessError - def receiverClass = qualifier.tpe.widenTermRefExpr.finalResultType.typeSymbol + def receiverClass = qualifier.tpe.typeSymbol if (sym.is(Module)) { genLoadQualUnlessElidable() genLoadModule(tree) diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala index 98ea6e0c5c44..396d85a8c58a 100644 --- a/compiler/src/dotty/tools/dotc/ast/tpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala @@ -1383,7 +1383,11 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { /** Recover identifier prefix (e.g. this) if it exists */ def desugarIdentPrefix(tree: Ident)(using Context): Tree = tree.tpe match { case TermRef(prefix: TermRef, _) => - ref(prefix) + prefix.info match + case mt: MethodType if mt.paramInfos.isEmpty && mt.resultType.typeSymbol.is(Module) => + ref(mt.resultType.typeSymbol.sourceModule) + case _ => + ref(prefix) case TermRef(prefix: ThisType, _) => This(prefix.cls) case _ =>