Skip to content

Enable -Ycheck:all #4183

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 8 commits into from
Apr 17, 2018
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
13 changes: 7 additions & 6 deletions compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
Original file line number Diff line number Diff line change
Expand Up @@ -170,14 +170,15 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
case _ => false
}

/** Is this argument node of the form <expr> : _* ?
/** Is this argument node of the form <expr> : _*, or is it a reference to
* such an argument ? The latter case can happen when an argument is lifted.
*/
def isWildcardStarArg(tree: Tree)(implicit ctx: Context): Boolean = unbind(tree) match {
case Typed(Ident(nme.WILDCARD_STAR), _) => true
case Typed(_, Ident(tpnme.WILDCARD_STAR)) => true
case Typed(_, tpt: TypeTree) => tpt.hasType && tpt.tpe.isRepeatedParam
case Typed(_, tpt: TypeTree) => tpt.typeOpt.isRepeatedParam
case NamedArg(_, arg) => isWildcardStarArg(arg)
case _ => false
case arg => arg.typeOpt.widen.isRepeatedParam
}

/** If this tree has type parameters, those. Otherwise Nil.
Expand Down Expand Up @@ -317,7 +318,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
* Idempotent if running the statement a second time has no side effects
* Impure otherwise
*/
private def statPurity(tree: Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
def statPurity(tree: Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
case EmptyTree
| TypeDef(_, _)
| Import(_, _)
Expand All @@ -342,7 +343,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
* takes a different code path than all to follow; but they are idempotent
* because running the expression a second time gives the cached result.
*/
private def exprPurity(tree: Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
def exprPurity(tree: Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
case EmptyTree
| This(_)
| Super(_, _)
Expand Down Expand Up @@ -397,7 +398,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
* @DarkDimius: need to make sure that lazy accessor methods have Lazy and Stable
* flags set.
*/
private def refPurity(tree: Tree)(implicit ctx: Context): PurityLevel =
def refPurity(tree: Tree)(implicit ctx: Context): PurityLevel =
if (!tree.tpe.widen.isParameterless || tree.symbol.is(Erased)) SimplyPure
else if (!tree.symbol.isStable) Impure
else if (tree.symbol.is(Lazy)) Idempotent // TODO add Module flag, sinxce Module vals or not Lazy from the start.
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
return "FunProto(" ~ argsText ~ "):" ~ toText(resultType)
case tp: IgnoredProto =>
return "?"
case tp @ PolyProto(targs, resType) =>
return "PolyProto(" ~ toTextGlobal(targs, ", ") ~ "): " ~ toText(resType)
case _ =>
}
super.toText(tp)
Expand Down
13 changes: 9 additions & 4 deletions compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,8 @@ class TreeChecker extends Phase with SymTransformer {

if (sym.isClass && !sym.isAbsent) {
val validSuperclass = sym.isPrimitiveValueClass || defn.syntheticCoreClasses.contains(sym) ||
(sym eq defn.ObjectClass) || (sym is NoSuperClass) || (sym.asClass.superClass.exists)
(sym eq defn.ObjectClass) || (sym is NoSuperClass) || (sym.asClass.superClass.exists) ||
sym.isRefinementClass

assert(validSuperclass, i"$sym has no superclass set")
testDuplicate(sym, seenClasses, "class")
Expand All @@ -97,7 +98,10 @@ class TreeChecker extends Phase with SymTransformer {
def phaseName: String = "Ycheck"

def run(implicit ctx: Context): Unit = {
check(ctx.allPhases, ctx)
if (ctx.settings.YtestPickler.value && ctx.phase.prev.isInstanceOf[Pickler])
ctx.echo("Skipping Ycheck after pickling with -Ytest-pickler, the returned tree contains stale symbols")
else
check(ctx.allPhases, ctx)
}

private def previousPhases(phases: List[Phase])(implicit ctx: Context): List[Phase] = phases match {
Expand Down Expand Up @@ -305,7 +309,7 @@ class TreeChecker extends Phase with SymTransformer {

override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = {
assert(tree.isTerm || !ctx.isAfterTyper, tree.show + " at " + ctx.phase)
assert(tree.isType || !needsSelect(tree.tpe), i"bad type ${tree.tpe} for $tree # ${tree.uniqueId}")
assert(tree.isType || ctx.mode.is(Mode.Pattern) && untpd.isWildcardArg(tree) || !needsSelect(tree.tpe), i"bad type ${tree.tpe} for $tree # ${tree.uniqueId}")
assertDefined(tree)

checkNotRepeated(super.typedIdent(tree, pt))
Expand Down Expand Up @@ -443,7 +447,8 @@ class TreeChecker extends Phase with SymTransformer {
if (ctx.mode.isExpr &&
!tree.isEmpty &&
!isPrimaryConstructorReturn &&
!pt.isInstanceOf[FunProto])
!pt.isInstanceOf[FunProto] &&
!pt.isInstanceOf[PolyProto])
assert(tree.tpe <:< pt, {
val mismatch = err.typeMismatchMsg(tree.tpe, pt)
i"""|${mismatch.msg}
Expand Down
14 changes: 9 additions & 5 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import StdNames._
import NameOps._
import Symbols._
import Trees._
import TreeInfo._
import ProtoTypes._
import Constants._
import Scopes._
Expand Down Expand Up @@ -601,17 +602,20 @@ trait Checking {
}
}

/** Check that `tree` is a pure expression of constant type */
def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context): Unit =
/** Check that `tree` can be marked `inline` */
def checkInlineConformant(tree: Tree, isFinal: Boolean, what: => String)(implicit ctx: Context): Unit = {
// final vals can be marked inline even if they're not pure, see Typer#patchFinalVals
val purityLevel = if (isFinal) Idempotent else Pure
tree.tpe match {
case tp: TermRef if tp.symbol.is(InlineParam) => // ok
case tp => tp.widenTermRefExpr match {
case tp: ConstantType if isPureExpr(tree) => // ok
case tp if defn.isFunctionType(tp) && isPureExpr(tree) => // ok
case tp: ConstantType if exprPurity(tree) >= purityLevel => // ok
case tp if defn.isFunctionType(tp) && exprPurity(tree) >= purityLevel => // ok
case _ =>
if (!ctx.erasedTypes) ctx.error(em"$what must be a constant expression or a function", tree.pos)
}
}
}

/** Check that class does not declare same symbol twice */
def checkNoDoubleDeclaration(cls: Symbol)(implicit ctx: Context): Unit = {
Expand Down Expand Up @@ -867,7 +871,7 @@ trait NoChecking extends ReChecking {
override def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp
override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = ()
override def checkFeasibleParent(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp
override def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context) = ()
override def checkInlineConformant(tree: Tree, isFinal: Boolean, what: => String)(implicit ctx: Context) = ()
override def checkNoDoubleDeclaration(cls: Symbol)(implicit ctx: Context): Unit = ()
override def checkParentCall(call: Tree, caller: ClassSymbol)(implicit ctx: Context) = ()
override def checkSimpleKinded(tpt: Tree)(implicit ctx: Context): Tree = tpt
Expand Down
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1371,7 +1371,7 @@ class Typer extends Namer
}
val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym)
if (sym.is(Inline, butNot = DeferredOrTermParamOrAccessor))
checkInlineConformant(rhs1, em"right-hand side of inline $sym")
checkInlineConformant(rhs1, isFinal = sym.is(Final), em"right-hand side of inline $sym")
patchIfLazy(vdef1)
patchFinalVals(vdef1)
vdef1
Expand All @@ -1392,7 +1392,7 @@ class Typer extends Namer
* and instead return the value. This seemingly minor optimization has huge effect on initialization
* order and the values that can be observed during superconstructor call
*
* see remark about idempotency in PostTyper#normalizeTree
* see remark about idempotency in TreeInfo#constToLiteral
*/
private def patchFinalVals(vdef: ValDef)(implicit ctx: Context): Unit = {
def isFinalInlinableVal(sym: Symbol): Boolean = {
Expand Down Expand Up @@ -2329,7 +2329,7 @@ class Typer extends Namer
}
else if (tree.tpe <:< pt) {
if (pt.hasAnnotation(defn.InlineParamAnnot))
checkInlineConformant(tree, "argument to inline parameter")
checkInlineConformant(tree, isFinal = false, "argument to inline parameter")
if (Inliner.hasBodyToInline(tree.symbol) &&
!ctx.owner.ownersIterator.exists(_.isInlineMethod) &&
!ctx.settings.YnoInline.value &&
Expand Down
2 changes: 1 addition & 1 deletion compiler/test/dotty/tools/vulpix/TestConfiguration.scala
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ object TestConfiguration {
}

// Ideally should be Ycheck:all
val yCheckOptions = Array("-Ycheck:elimJavaPackages,refchecks,splitter,arrayConstructors,erasure,capturedVars,getClass,elimStaticThis,labelDef")
val yCheckOptions = Array("-Ycheck:all")

val basicDefaultOptions = checkOptions ++ noCheckOptions ++ yCheckOptions
val defaultUnoptimised = TestFlags(classPath, runClassPath, basicDefaultOptions)
Expand Down
3 changes: 3 additions & 0 deletions tests/pos/i3971.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
object BadInlineConstCheck {
final val MaxSize = Int.MaxValue + 0
}