Skip to content

Tighten Ycheck of type ascriptions #12513

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 1 commit into from
May 25, 2021
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
24 changes: 24 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,30 @@ class TreeChecker extends Phase with SymTransformer {
assert(tree.qual.tpe.isInstanceOf[ThisType], i"expect prefix of Super to be This, actual = ${tree.qual}")
super.typedSuper(tree, pt)

override def typedTyped(tree: untpd.Typed, pt: Type)(using Context): Tree =
val tpt1 = checkSimpleKinded(typedType(tree.tpt))
val expr1 = tree.expr match
case id: untpd.Ident if (ctx.mode is Mode.Pattern) && untpd.isVarPattern(id) && (id.name == nme.WILDCARD || id.name == nme.WILDCARD_STAR) =>
tree.expr.withType(tpt1.tpe)
case _ =>
var pt1 = tpt1.tpe
if pt1.isRepeatedParam then
pt1 = pt1.translateFromRepeated(toArray = tree.expr.typeOpt.derivesFrom(defn.ArrayClass))
val isAfterInlining =
val inliningPhase = ctx.base.inliningPhase
inliningPhase.exists && ctx.phase.id > inliningPhase.id
if isAfterInlining then
// The staging phase destroys in PCPCheckAndHeal the property that
// tree.expr.tpe <:< pt1. A test case where this arises is run-macros/enum-nat-macro.
// We should follow up why this happens. If the problem is fixed, we can
// drop the isAfterInlining special case. To reproduce the problem, just
// change the condition from `isAfterInlining` to `false`.
typed(tree.expr)
else
//println(i"typing $tree, ${tree.expr.typeOpt}, $pt1, ${ctx.mode is Mode.Pattern}")
typed(tree.expr, pt1)
untpd.cpy.Typed(tree)(expr1, tpt1).withType(tree.typeOpt)

private def checkOwner(tree: untpd.Tree)(using Context): Unit = {
def ownerMatches(symOwner: Symbol, ctxOwner: Symbol): Boolean =
symOwner == ctxOwner ||
Expand Down
23 changes: 15 additions & 8 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -814,11 +814,9 @@ class Typer extends Namer
val underlyingTreeTpe =
if (isRepeatedParamType(tpt)) TypeTree(defn.SeqType.appliedTo(pt :: Nil))
else tpt

val expr1 =
if (isRepeatedParamType(tpt)) tree.expr.withType(defn.SeqType.appliedTo(pt :: Nil))
else if (isWildcard) tree.expr.withType(tpt.tpe)
else typed(tree.expr, tpt.tpe.widenSkolem)
if isWildcard then tree.expr.withType(underlyingTreeTpe.tpe)
else typed(tree.expr, underlyingTreeTpe.tpe.widenSkolem)
assignType(cpy.Typed(tree)(expr1, tpt), underlyingTreeTpe)
.withNotNullInfo(expr1.notNullInfo)
}
Expand All @@ -844,8 +842,10 @@ class Typer extends Namer
// We need to make sure its type is no longer nullable
expr0.castToNonNullable
else expr0
val fromCls = if expr1.tpe.derivesFrom(defn.ArrayClass)
then defn.ArrayClass else defn.SeqClass
val fromCls =
if expr1.tpe.derivesFrom(defn.ArrayClass)
then defn.ArrayClass
else defn.SeqClass
val tpt1 = TypeTree(expr1.tpe.widen.translateToRepeated(fromCls)).withSpan(tree.tpt.span)
assignType(cpy.Typed(tree)(expr1, tpt1), tpt1)
}
Expand Down Expand Up @@ -1055,7 +1055,14 @@ class Typer extends Namer
val expr1 = ascribeType(expr, pt)
cpy.Block(block)(stats, expr1) withType expr1.tpe // no assignType here because avoid is redundant
case _ =>
Typed(tree, TypeTree(pt.simplified))
val target = pt.simplified
if tree.tpe <:< target then Typed(tree, TypeTree(pt.simplified))
else
// This case should not normally arise. It currently does arise in test cases
// pos/t4080b.scala and pos/i7067.scala. In that case, a type ascription is wrong
// and would not pass Ycheck. We have to use a cast instead. TODO: follow-up why
// the cases arise and eliminate them, if possible.
tree.cast(target)
}
def noLeaks(t: Tree): Boolean = escapingRefs(t, localSyms).isEmpty
if (noLeaks(tree)) tree
Expand Down Expand Up @@ -3693,7 +3700,7 @@ class Typer extends Namer
gadts.println(i"GADT-approximated $wtp ~~ $gadtApprox")
if pt.isMatchedBy(gadtApprox) then
gadts.println(i"Member selection healed by GADT approximation")
tpd.Typed(tree, TypeTree(gadtApprox))
tree.cast(gadtApprox)
else tree
else tree // other adaptations for selections are handled in typedSelect
case _ if ctx.mode.is(Mode.ImplicitsEnabled) && tree.tpe.isValueType =>
Expand Down
3 changes: 3 additions & 0 deletions compiler/test/dotc/pos-from-tasty.blacklist
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,6 @@ rbtree.scala

# transitive reduction of match types
i10511.scala

# Violates tightened condition in Retyper#typedTyped
i11247.scala