Skip to content

Fix #7013: Check PCP for all class references #7015

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Aug 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 22 additions & 15 deletions compiler/src/dotty/tools/dotc/transform/PCPCheckAndHeal.scala
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,12 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
/** Is a reference to a class but not `this.type` */
def isClassRef = sym.isClass && !tp.isInstanceOf[ThisType]

if (sym.exists && !sym.isStaticOwner && !isClassRef && !levelOK(sym))
if (!sym.exists || levelOK(sym))
None
else if (!sym.isStaticOwner && !isClassRef)
tryHeal(sym, tp, pos)
else if (!sym.owner.isStaticOwner) // non-top level class reference that is phase inconsistent
levelError(sym, tp, pos, "")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will a member class be accepted or not? Maybe add a test for that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They will not. I added a regression test for it.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe update the comment too --- it's not only about local classes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

else
None
}
Expand Down Expand Up @@ -170,17 +174,6 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
* to be added to the "inconsistent phase" message.
*/
protected def tryHeal(sym: Symbol, tp: Type, pos: SourcePosition)(implicit ctx: Context): Option[Tree] = {
def levelError(errMsg: String) = {
def symStr =
if (!tp.isInstanceOf[ThisType]) sym.show
else if (sym.is(ModuleClass)) sym.sourceModule.show
else i"${sym.name}.this"
ctx.error(
em"""access to $symStr from wrong staging level:
| - the definition is at level ${levelOf(sym).getOrElse(0)},
| - but the access is at level $level.$errMsg""", pos)
None
}
tp match {
case tp: TypeRef =>
if (level == -1) {
Expand All @@ -193,19 +186,33 @@ class PCPCheckAndHeal(@constructorOnly ictx: Context) extends TreeMapWithStages(
case _: TermRef =>
Some(tag.select(tpnme.splice))
case _: SearchFailureType =>
levelError(i"""
levelError(sym, tp, pos,
i"""
|
| The access would be accepted with the right type tag, but
| ${ctx.typer.missingArgMsg(tag, reqType, "")}""")
case _ =>
levelError(i"""
levelError(sym, tp, pos,
i"""
|
| The access would be accepted with an implict $reqType""")
}
}
case _ =>
levelError("")
levelError(sym, tp, pos, "")
}
}

private def levelError(sym: Symbol, tp: Type, pos: SourcePosition, errMsg: String) given Context = {
def symStr =
if (!tp.isInstanceOf[ThisType]) sym.show
else if (sym.is(ModuleClass)) sym.sourceModule.show
else i"${sym.name}.this"
the[Context].error(
em"""access to $symStr from wrong staging level:
| - the definition is at level ${levelOf(sym).getOrElse(0)},
| - but the access is at level $level.$errMsg""", pos)
None
}

}
6 changes: 6 additions & 0 deletions tests/neg/i7013.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import quoted._

def foo() given QuoteContext = {
class C
'[C] // error
}
8 changes: 8 additions & 0 deletions tests/neg/i7013b.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import quoted._

class Foo {
class Bar
def foo() given QuoteContext = {
'[Bar] // error
}
}
6 changes: 6 additions & 0 deletions tests/neg/i7013c.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import quoted._

def foo() given QuoteContext = {
type C
'[C] // error
}