From a63f92c54dac2ec4a511368dc8d07630dafcf3f2 Mon Sep 17 00:00:00 2001 From: Martin Odersky Date: Mon, 22 Jun 2020 17:15:24 +0200 Subject: [PATCH] Fix #8874: Strip opaque types when checking self type conformance --- .../dotty/tools/dotc/transform/SymUtils.scala | 11 +++++++++++ .../src/dotty/tools/dotc/typer/Checking.scala | 16 ++++------------ .../src/dotty/tools/dotc/typer/RefChecks.scala | 4 ++-- tests/pos/i8874.scala | 6 ++++++ 4 files changed, 23 insertions(+), 14 deletions(-) create mode 100644 tests/pos/i8874.scala diff --git a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala index a3b55131865b..895a66e0b700 100644 --- a/compiler/src/dotty/tools/dotc/transform/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/transform/SymUtils.scala @@ -226,4 +226,15 @@ class SymUtils(val self: Symbol) extends AnyVal { && self.owner.is(Module) && self.owner.linkedClass.is(Case) && self.owner.linkedClass.isDeclaredInfix + + /** The declared self type of this class, as seen from `site`, stripping + * all refinements for opaque types. + */ + def declaredSelfTypeAsSeenFrom(site: Type)(using Context) = + def (tp: Type).stripOpaques: Type = tp match + case RefinedType(parent, name, _) if self.info.decl(name).symbol.isOpaqueAlias => + parent.stripOpaques + case _ => + tp + self.asClass.givenSelfType.stripOpaques.asSeenFrom(site, self) } diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index 835a57068c06..1d8e5707f2cd 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -169,27 +169,19 @@ object Checking { * and that the instance conforms to the self type of the created class. */ def checkInstantiable(tp: Type, posd: Positioned)(using Context): Unit = - tp.underlyingClassRef(refinementOK = false) match { + tp.underlyingClassRef(refinementOK = false) match case tref: TypeRef => val cls = tref.symbol if (cls.isOneOf(AbstractOrTrait)) ctx.error(CantInstantiateAbstractClassOrTrait(cls, isTrait = cls.is(Trait)), posd.sourcePos) - if (!cls.is(Module)) { - def (tp: Type).stripOpaques: Type = tp match - case RefinedType(parent, name, _) if cls.info.decl(name).symbol.isOpaqueAlias => - parent.stripOpaques - case _ => - tp + if !cls.is(Module) then // Create a synthetic singleton type instance, and check whether // it conforms to the self type of the class as seen from that instance. val stp = SkolemType(tp) - val selfType = - cls.asClass.givenSelfType.stripOpaques.asSeenFrom(stp, cls) - if (selfType.exists && !(stp <:< selfType)) + val selfType = cls.declaredSelfTypeAsSeenFrom(stp) + if selfType.exists && !(stp <:< selfType) then ctx.error(DoesNotConformToSelfTypeCantBeInstantiated(tp, selfType), posd.sourcePos) - } case _ => - } /** Check that type `tp` is realizable. */ def checkRealizable(tp: Type, posd: Positioned, what: String = "path")(using Context): Unit = { diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 41f720a9ae67..591d15eef5de 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -95,8 +95,8 @@ object RefChecks { private def checkParents(cls: Symbol)(using Context): Unit = cls.info match { case cinfo: ClassInfo => def checkSelfConforms(other: ClassSymbol, category: String, relation: String) = { - val otherSelf = other.givenSelfType.asSeenFrom(cls.thisType, other.classSymbol) - if (otherSelf.exists && !(cinfo.selfType <:< otherSelf)) + val otherSelf = other.declaredSelfTypeAsSeenFrom(cls.thisType) + if otherSelf.exists && !(cinfo.selfType <:< otherSelf) then ctx.error(DoesNotConformToSelfType(category, cinfo.selfType, cls, otherSelf, relation, other.classSymbol), cls.sourcePos) } diff --git a/tests/pos/i8874.scala b/tests/pos/i8874.scala new file mode 100644 index 000000000000..cc19ee330ac0 --- /dev/null +++ b/tests/pos/i8874.scala @@ -0,0 +1,6 @@ +trait Abc: + opaque type Log = Double + +class AbcClass extends Abc + +val v = new AbcClass \ No newline at end of file