From 194ad8ed0e6ab19402b3512872d6da8f99bb944a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Doeraene?= Date: Thu, 23 Nov 2023 11:19:32 +0100 Subject: [PATCH] Fix #19019: Always type self ValDefs in their outer context. --- .../dotty/tools/dotc/core/ContextOps.scala | 15 ++++++-- tests/printing/i19019.check | 37 +++++++++++++++++++ tests/printing/i19019.scala | 23 ++++++++++++ 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 tests/printing/i19019.check create mode 100644 tests/printing/i19019.scala diff --git a/compiler/src/dotty/tools/dotc/core/ContextOps.scala b/compiler/src/dotty/tools/dotc/core/ContextOps.scala index 8e0b022b891e..920da377f9b4 100644 --- a/compiler/src/dotty/tools/dotc/core/ContextOps.scala +++ b/compiler/src/dotty/tools/dotc/core/ContextOps.scala @@ -80,12 +80,19 @@ object ContextOps: } /** A fresh local context with given tree and owner. - * Owner might not exist (can happen for self valdefs), in which case - * no owner is set in result context - */ + * + * #19019 Self valdefs must always keep their enclosing ctx.owner. They + * can be NoSymbol or having a symbol with the SelfName flag, depending on + * whether they have an explicit name or not. In either case, we avoid + * `setOwner`. + * + * The owner might also not exist for other kinds of trees, such as + * `LambdaTypeTree` and `TermLambdaTypeTree`. In these cases, we also + * keep the enclosing owner. + */ def localContext(tree: untpd.Tree, owner: Symbol): FreshContext = inContext(ctx) { val freshCtx = ctx.fresh.setTree(tree) - if owner.exists then freshCtx.setOwner(owner) else freshCtx + if owner.exists && !owner.is(SelfName) then freshCtx.setOwner(owner) else freshCtx } /** Context where `sym` is defined, assuming we are in a nested context. */ diff --git a/tests/printing/i19019.check b/tests/printing/i19019.check new file mode 100644 index 000000000000..1cbaef492ed8 --- /dev/null +++ b/tests/printing/i19019.check @@ -0,0 +1,37 @@ +[[syntax trees at end of typer]] // tests/printing/i19019.scala +package { + final lazy module val ObjectWithSelf: ObjectWithSelf = new ObjectWithSelf() + final module class ObjectWithSelf() extends Object() { + this: ObjectWithSelf.type => + final lazy module val StaticObjectNoSelf: ObjectWithSelf.StaticObjectNoSelf + = new ObjectWithSelf.StaticObjectNoSelf() + final module class StaticObjectNoSelf() extends Object() { + this: ObjectWithSelf.StaticObjectNoSelf.type => + def foo: Any = this + } + final lazy module val StaticObjectWithSelf: + ObjectWithSelf.StaticObjectWithSelf = + new ObjectWithSelf.StaticObjectWithSelf() + final module class StaticObjectWithSelf() extends Object() { + self: ObjectWithSelf.StaticObjectWithSelf.type => + def foo: Any = self + } + class Container() extends Object() { + final lazy module val NonStaticObjectNoSelf: + Container.this.NonStaticObjectNoSelf = + new Container.this.NonStaticObjectNoSelf() + final module class NonStaticObjectNoSelf() extends Object() { + this: Container.this.NonStaticObjectNoSelf.type => + def foo: Any = this + } + final lazy module val NonStaticObjectWithSelf: + Container.this.NonStaticObjectWithSelf = + new Container.this.NonStaticObjectWithSelf() + final module class NonStaticObjectWithSelf() extends Object() { + self: Container.this.NonStaticObjectWithSelf.type => + def foo: Any = self + } + } + } +} + diff --git a/tests/printing/i19019.scala b/tests/printing/i19019.scala new file mode 100644 index 000000000000..b91089b8e00d --- /dev/null +++ b/tests/printing/i19019.scala @@ -0,0 +1,23 @@ +object ObjectWithSelf: + object StaticObjectNoSelf: + def foo: Any = this + end StaticObjectNoSelf + + object StaticObjectWithSelf: + self => + + def foo: Any = self + end StaticObjectWithSelf + + class Container: + object NonStaticObjectNoSelf: + def foo: Any = this + end NonStaticObjectNoSelf + + object NonStaticObjectWithSelf: + self => + + def foo: Any = self + end NonStaticObjectWithSelf + end Container +end ObjectWithSelf