From 4e695fb5559f28fcd95396a02bf8d778741a5c07 Mon Sep 17 00:00:00 2001 From: Guillaume Martres Date: Mon, 23 Jul 2018 22:46:09 +0200 Subject: [PATCH] Workaround #4819: Avoid creating incorrect JointRefDenotations When merging a denotation with a PolyType and a denotation with a MethodType, `infoMeet` will return the MethodType info, but the symbol that is then used to create the `JointRefDenotation` can come from either denotation, if it comes from the PolyType one, the resulting denotation is inconsistent, this resulted in RefChecks errors. We fix this by making `preferSym` consistent with `infoMeet`. This is only a workaround and not a proper fix for #4819 as it doesn't allow tests/neg/i4819.scala to compile, see the comments in the file. --- .../src/dotty/tools/dotc/core/Denotations.scala | 5 ++++- tests/neg/i4819.scala | 16 ++++++++++++++++ tests/pos/i4819.scala | 12 ++++++++++++ 3 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i4819.scala create mode 100644 tests/pos/i4819.scala diff --git a/compiler/src/dotty/tools/dotc/core/Denotations.scala b/compiler/src/dotty/tools/dotc/core/Denotations.scala index 6e5c80e4d7d2..c84313ccae0e 100644 --- a/compiler/src/dotty/tools/dotc/core/Denotations.scala +++ b/compiler/src/dotty/tools/dotc/core/Denotations.scala @@ -490,7 +490,9 @@ object Denotations { * 4. The access boundary of sym2 is properly contained in the access * boundary of sym1. For protected access, we count the enclosing * package as access boundary. - * 5. sym1 a method but sym2 is not. + * 5. sym1 is a method but sym2 is not. + * 6. sym1 is a non-polymorphic method but sym2 is a polymorphic method. + * (to be consistent with infoMeet, see #4819) * The aim of these criteria is to give some disambiguation on access which * - does not depend on textual order or other arbitrary choices * - minimizes raising of doubleDef errors @@ -505,6 +507,7 @@ object Denotations { accessBoundary(sym2).isProperlyContainedIn(accessBoundary(sym1)) || sym2.is(Bridge) && !sym1.is(Bridge) || sym1.is(Method) && !sym2.is(Method)) || + sym1.info.isInstanceOf[MethodType] && sym2.info.isInstanceOf[PolyType] || sym1.info.isErroneous) /** Sym preference provided types also override */ diff --git a/tests/neg/i4819.scala b/tests/neg/i4819.scala new file mode 100644 index 000000000000..224682fc000c --- /dev/null +++ b/tests/neg/i4819.scala @@ -0,0 +1,16 @@ +trait One[X] { + def concat(suffix: Int): X = ??? +} + +trait Two[Y <: Foo] { + def concat[Dummy](suffix: Int): Y = ??? +} + +class Foo extends One[Foo] with Two[Foo] { + concat(0) // OK + + // TODO: This does not typecheck because the polymorphic overload is masked + // (we merge the denotations for both overloads into one and always prefer + // MethodType to PolyType, instead we should return a MultiDenotation). See #4819. + concat[Int](0) // error (that should actually not be an error) +} diff --git a/tests/pos/i4819.scala b/tests/pos/i4819.scala new file mode 100644 index 000000000000..508c579a8753 --- /dev/null +++ b/tests/pos/i4819.scala @@ -0,0 +1,12 @@ +trait One[X] { + def concat(suffix: Int): X = ??? +} + +trait Two[Y <: Foo] { + def concat[Dummy](suffix: Int): Y = ??? +} + +class Foo extends One[Foo] with Two[Foo] { + concat(0) // OK + // See also tests/neg/i4819.scala +}