Skip to content

Commit 663b4b9

Browse files
authored
Merge pull request #4183 from dotty-staging/fix/Ycheck-frontend-2
Enable -Ycheck:all
2 parents c28ea78 + 35c13d8 commit 663b4b9

File tree

7 files changed

+34
-19
lines changed

7 files changed

+34
-19
lines changed

compiler/src/dotty/tools/dotc/ast/TreeInfo.scala

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -170,14 +170,15 @@ trait TreeInfo[T >: Untyped <: Type] { self: Trees.Instance[T] =>
170170
case _ => false
171171
}
172172

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

183184
/** If this tree has type parameters, those. Otherwise Nil.
@@ -317,7 +318,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
317318
* Idempotent if running the statement a second time has no side effects
318319
* Impure otherwise
319320
*/
320-
private def statPurity(tree: Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
321+
def statPurity(tree: Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
321322
case EmptyTree
322323
| TypeDef(_, _)
323324
| Import(_, _)
@@ -342,7 +343,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
342343
* takes a different code path than all to follow; but they are idempotent
343344
* because running the expression a second time gives the cached result.
344345
*/
345-
private def exprPurity(tree: Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
346+
def exprPurity(tree: Tree)(implicit ctx: Context): PurityLevel = unsplice(tree) match {
346347
case EmptyTree
347348
| This(_)
348349
| Super(_, _)
@@ -397,7 +398,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
397398
* @DarkDimius: need to make sure that lazy accessor methods have Lazy and Stable
398399
* flags set.
399400
*/
400-
private def refPurity(tree: Tree)(implicit ctx: Context): PurityLevel =
401+
def refPurity(tree: Tree)(implicit ctx: Context): PurityLevel =
401402
if (!tree.tpe.widen.isParameterless || tree.symbol.is(Erased)) SimplyPure
402403
else if (!tree.symbol.isStable) Impure
403404
else if (tree.symbol.is(Lazy)) Idempotent // TODO add Module flag, sinxce Module vals or not Lazy from the start.

compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,8 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
218218
return "FunProto(" ~ argsText ~ "):" ~ toText(resultType)
219219
case tp: IgnoredProto =>
220220
return "?"
221+
case tp @ PolyProto(targs, resType) =>
222+
return "PolyProto(" ~ toTextGlobal(targs, ", ") ~ "): " ~ toText(resType)
221223
case _ =>
222224
}
223225
super.toText(tp)

compiler/src/dotty/tools/dotc/transform/TreeChecker.scala

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ class TreeChecker extends Phase with SymTransformer {
8080

8181
if (sym.isClass && !sym.isAbsent) {
8282
val validSuperclass = sym.isPrimitiveValueClass || defn.syntheticCoreClasses.contains(sym) ||
83-
(sym eq defn.ObjectClass) || (sym is NoSuperClass) || (sym.asClass.superClass.exists)
83+
(sym eq defn.ObjectClass) || (sym is NoSuperClass) || (sym.asClass.superClass.exists) ||
84+
sym.isRefinementClass
8485

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

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

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

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

311315
checkNotRepeated(super.typedIdent(tree, pt))
@@ -443,7 +447,8 @@ class TreeChecker extends Phase with SymTransformer {
443447
if (ctx.mode.isExpr &&
444448
!tree.isEmpty &&
445449
!isPrimaryConstructorReturn &&
446-
!pt.isInstanceOf[FunProto])
450+
!pt.isInstanceOf[FunProto] &&
451+
!pt.isInstanceOf[PolyProto])
447452
assert(tree.tpe <:< pt, {
448453
val mismatch = err.typeMismatchMsg(tree.tpe, pt)
449454
i"""|${mismatch.msg}

compiler/src/dotty/tools/dotc/typer/Checking.scala

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import StdNames._
1313
import NameOps._
1414
import Symbols._
1515
import Trees._
16+
import TreeInfo._
1617
import ProtoTypes._
1718
import Constants._
1819
import Scopes._
@@ -601,17 +602,20 @@ trait Checking {
601602
}
602603
}
603604

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

616620
/** Check that class does not declare same symbol twice */
617621
def checkNoDoubleDeclaration(cls: Symbol)(implicit ctx: Context): Unit = {
@@ -867,7 +871,7 @@ trait NoChecking extends ReChecking {
867871
override def checkClassType(tp: Type, pos: Position, traitReq: Boolean, stablePrefixReq: Boolean)(implicit ctx: Context): Type = tp
868872
override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = ()
869873
override def checkFeasibleParent(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp
870-
override def checkInlineConformant(tree: Tree, what: => String)(implicit ctx: Context) = ()
874+
override def checkInlineConformant(tree: Tree, isFinal: Boolean, what: => String)(implicit ctx: Context) = ()
871875
override def checkNoDoubleDeclaration(cls: Symbol)(implicit ctx: Context): Unit = ()
872876
override def checkParentCall(call: Tree, caller: ClassSymbol)(implicit ctx: Context) = ()
873877
override def checkSimpleKinded(tpt: Tree)(implicit ctx: Context): Tree = tpt

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,7 +1371,7 @@ class Typer extends Namer
13711371
}
13721372
val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym)
13731373
if (sym.is(Inline, butNot = DeferredOrTermParamOrAccessor))
1374-
checkInlineConformant(rhs1, em"right-hand side of inline $sym")
1374+
checkInlineConformant(rhs1, isFinal = sym.is(Final), em"right-hand side of inline $sym")
13751375
patchIfLazy(vdef1)
13761376
patchFinalVals(vdef1)
13771377
vdef1
@@ -1392,7 +1392,7 @@ class Typer extends Namer
13921392
* and instead return the value. This seemingly minor optimization has huge effect on initialization
13931393
* order and the values that can be observed during superconstructor call
13941394
*
1395-
* see remark about idempotency in PostTyper#normalizeTree
1395+
* see remark about idempotency in TreeInfo#constToLiteral
13961396
*/
13971397
private def patchFinalVals(vdef: ValDef)(implicit ctx: Context): Unit = {
13981398
def isFinalInlinableVal(sym: Symbol): Boolean = {
@@ -2329,7 +2329,7 @@ class Typer extends Namer
23292329
}
23302330
else if (tree.tpe <:< pt) {
23312331
if (pt.hasAnnotation(defn.InlineParamAnnot))
2332-
checkInlineConformant(tree, "argument to inline parameter")
2332+
checkInlineConformant(tree, isFinal = false, "argument to inline parameter")
23332333
if (Inliner.hasBodyToInline(tree.symbol) &&
23342334
!ctx.owner.ownersIterator.exists(_.isInlineMethod) &&
23352335
!ctx.settings.YnoInline.value &&

compiler/test/dotty/tools/vulpix/TestConfiguration.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ object TestConfiguration {
4545
}
4646

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

5050
val basicDefaultOptions = checkOptions ++ noCheckOptions ++ yCheckOptions
5151
val defaultUnoptimised = TestFlags(classPath, runClassPath, basicDefaultOptions)

tests/pos/i3971.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
object BadInlineConstCheck {
2+
final val MaxSize = Int.MaxValue + 0
3+
}

0 commit comments

Comments
 (0)