diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index e2dee2c8accc..85343fb1ef65 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -719,6 +719,22 @@ trait Checking { checkNoForwardDependencies(vparams1) case Nil => } + + /** Check that all named type that form part of this type have a denotation. + * Called on inferred (result) types of ValDefs and DefDefs. + * This could fail for types where the member was originally available as part + * of the self type, yet is no longer visible once the `this` has been replaced + * by some other prefix. See neg/i3083.scala + */ + def checkMembersOK(tp: Type, pos: Position)(implicit ctx: Context): Type = { + val check: Type => Unit = { + case ref: NamedType if !ref.denot.exists => + ctx.error(em"$ref is not defined in inferred type $tp", pos) + case _ => + } + tp.foreachPart(check, stopAtStatic = true) + tp + } } trait NoChecking extends Checking { @@ -738,4 +754,5 @@ trait NoChecking extends Checking { override def checkTraitInheritance(parentSym: Symbol, cls: ClassSymbol, pos: Position)(implicit ctx: Context) = () override def checkCaseInheritance(parentSym: Symbol, caseCls: ClassSymbol, pos: Position)(implicit ctx: Context) = () override def checkNoForwardDependencies(vparams: List[ValDef])(implicit ctx: Context): Unit = () + override def checkMembersOK(tp: Type, pos: Position)(implicit ctx: Context): Type = tp } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 07ca5c04deec..8433425e225b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1103,7 +1103,7 @@ class Namer { typer: Typer => case _: untpd.DerivedTypeTree => WildcardType case TypeTree() => - inferredType + checkMembersOK(inferredType, mdef.pos) case DependentTypeTree(tpFun) => tpFun(paramss.head) case TypedSplice(tpt: TypeTree) if !isFullyDefined(tpt.tpe, ForceDegree.none) => diff --git a/tests/neg/i3083.scala b/tests/neg/i3083.scala new file mode 100644 index 000000000000..916124db0517 --- /dev/null +++ b/tests/neg/i3083.scala @@ -0,0 +1,32 @@ + object Main { + + trait Literal { + type F[T] + def num(i: Int): F[Int] + } + + trait Addition { self: Literal => + def add(l: F[Int], r: F[Int]): F[Int] + } + + def expression(adder: Addition) = { + import adder._ + add(num(1), num(2)) // error // error (not found: num) + } + } + + object Minimized { + trait Literal { + type F[T] + } + + trait Addition { self: Literal => + def foo: F[Int] + } + + object Main { + def expression(adder: Addition) = { // error: adder.F is not defined in inferred type + adder.foo + } + } + } diff --git a/tests/pos/i3083.scala b/tests/pos/i3083.scala new file mode 100644 index 000000000000..fd8556554643 --- /dev/null +++ b/tests/pos/i3083.scala @@ -0,0 +1,15 @@ +object Minimized { + trait Literal { + type F[T] + } + + trait Addition { self: Literal => + def foo: F[Int] + } + + object Main { + def expression(adder: Addition & Literal) = { // error: adder.F is not defined in inferred type + adder.foo + } + } +}