diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index ab3bb6897ed2..1959ff851cad 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -8,6 +8,7 @@ import Symbols._, StdNames._, Trees._ import Decorators._, transform.SymUtils._ import NameKinds.{UniqueName, EvidenceParamName, DefaultGetterName} import typer.FrontEnd +import util.Property import collection.mutable.ListBuffer import reporting.diagnostic.messages._ import reporting.trace @@ -18,6 +19,11 @@ object desugar { import untpd._ import DesugarEnums._ + /** If a Select node carries this attachment, suppress the check + * that its type refers to an acessible symbol. + */ + val SuppressAccessCheck = new Property.Key[Unit] + /** Info of a variable in a pattern: The named tree and its type */ private type VarInfo = (NameTree, Tree) @@ -727,9 +733,11 @@ object desugar { fwd } val moduleName = tdef.name.toTermName - val aliasType = cpy.TypeDef(tdef)( - rhs = completeForwarder(Select(Ident(moduleName), tdef.name))) - val localType = tdef.withFlags(Synthetic | Opaque) + val localRef = Select(Ident(moduleName), tdef.name) + localRef.pushAttachment(SuppressAccessCheck, ()) + val aliasType = cpy.TypeDef(tdef)(rhs = completeForwarder(localRef)) + val localType = tdef.withMods(Modifiers(Synthetic | Opaque).withPrivateWithin(tdef.name)) + val companions = moduleDef(ModuleDef( moduleName, Template(emptyConstructor, Nil, EmptyValDef, localType :: Nil)) .withFlags(Synthetic | Opaque)) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index fda801f4091d..d90ef5134976 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -985,7 +985,7 @@ object SymDenotations { if (is(Module)) sourceModule else if (isOpaqueAlias) info match { - case TypeAlias(TypeRef(TermRef(prefix, _), _)) => prefix.termSymbol + case TypeAlias(TypeRef(prefix: TermRef, _)) => prefix.termSymbol } else registeredCompanion.sourceModule diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 38484974b650..feef330c4851 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -259,7 +259,8 @@ trait TypeAssigner { qualType = errorType(em"$qualType takes type parameters", qual1.pos) else if (!qualType.isInstanceOf[TermType]) qualType = errorType(em"$qualType is illegal as a selection prefix", qual1.pos) val ownType = selectionType(qualType, tree.name, tree.pos) - ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.pos) + if (tree.getAttachment(desugar.SuppressAccessCheck).isDefined) ownType + else ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.pos) } /** Type assignment method. Each method takes as parameters diff --git a/tests/neg/i5455.scala b/tests/neg/i5455.scala new file mode 100644 index 000000000000..13d44fa8058e --- /dev/null +++ b/tests/neg/i5455.scala @@ -0,0 +1,35 @@ +object Library { + + opaque type Nat = Int + + object Nat { + def apply(n: Int): Nat = { + require(n >= 0) + n + } + def times(x: Nat, y: Nat): Nat = x * y + def toInt(n: Nat): Int = n + + implicit class NatOps(val self: Nat) extends AnyVal { + def *(other: Nat): Nat = self * other + def toInt: Int = self.asInstanceOf + } + } +} + +object User extends App { + import Library._ + + val x = Nat(3) + val y = Nat(4) + + val a = x * y + val b = double1(x) + val c = double2(x) + + def double0(n: Nat): Nat = n * Nat(2) // ok + + def double1(n: Nat.Nat): Nat = n * Nat(2) // error + + def double2(n: Nat.Nat): Nat.Nat = n * Nat(2) // error // error +} \ No newline at end of file diff --git a/tests/run/i5455.scala b/tests/run/i5455.scala new file mode 100644 index 000000000000..ba3a71ec587e --- /dev/null +++ b/tests/run/i5455.scala @@ -0,0 +1,36 @@ +object Library { + + opaque type Nat = Int + + object Nat { + def apply(n: Int): Nat = { + require(n >= 0) + n + } + def times(x: Nat, y: Nat): Nat = x * y + def toInt(n: Nat): Int = n + + implicit class NatOps(val self: Nat) extends AnyVal { + def *(other: Nat): Nat = self * other + def toInt: Int = self.asInstanceOf + } + } +} + +object Test extends App { + import Library._ + + val x = Nat(3) + val y = Nat(4) + + val a = x * y + val b = double1(x) + val c = double2(x) + + assert(a.toInt == 12) + assert(b.toInt == 6) + assert(c.toInt == 6) + + def double1(n: Nat): Nat = n * Nat(2) + def double2(n: Nat): Nat = Nat.NatOps(n) * Nat(2) +} \ No newline at end of file