Skip to content

Commit df6f3f8

Browse files
committed
Tighten Ycheck of type ascriptions
We previously did not check that Typed nodes are type-correct, i.e. that the type of the expression conforms to the given type. Now we do. This uncovered problems in three different places: - for internal gadt ascriptions, where a cast should be used instead of a type ascription. - for avoidance, where two tests fail - for PCPCheckAndHeal, where one test fails For now, the logic in avoidance is changed so that we use a cast if an ascription is incorrect. But this should be fixed so that the cast is never needed, if possible. After phase inlining, we fall back to the old logic for typedTyped that does not check conformance. This is because of PCPCheckAndHeal. This problem should also be followed up.
1 parent f5bfed9 commit df6f3f8

File tree

2 files changed

+34
-14
lines changed

2 files changed

+34
-14
lines changed

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

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,18 +52,31 @@ class ReTyper extends Typer with ReChecking {
5252
override def typedSuper(tree: untpd.Super, pt: Type)(using Context): Tree =
5353
promote(tree)
5454

55-
override def typedTyped(tree: untpd.Typed, pt: Type)(using Context): Tree = {
55+
override def typedTyped(tree: untpd.Typed, pt: Type)(using Context): Tree =
5656
assertTyped(tree)
57-
5857
val tpt1 = checkSimpleKinded(typedType(tree.tpt))
59-
val expr1 = tree.expr match {
58+
val expr1 = tree.expr match
6059
case id: untpd.Ident if (ctx.mode is Mode.Pattern) && untpd.isVarPattern(id) && (id.name == nme.WILDCARD || id.name == nme.WILDCARD_STAR) =>
6160
tree.expr.withType(tpt1.tpe)
62-
case _ => typed(tree.expr)
63-
}
61+
case _ =>
62+
var pt1 = tpt1.tpe
63+
if pt1.isRepeatedParam then
64+
pt1 = pt1.translateFromRepeated(toArray = tree.expr.typeOpt.derivesFrom(defn.ArrayClass))
65+
val isAfterInlining =
66+
val inliningPhase = ctx.base.inliningPhase
67+
inliningPhase.exists && ctx.phase.id > inliningPhase.id
68+
if isAfterInlining then
69+
// The staging phase destroys in PCPCheckAndHeal the property that
70+
// tree.expr.tpe <:< pt1. A test case where this arises is run-macros/enum-nat-macro.
71+
// We should follow up why this happens. If the problem is fixed, we can
72+
// drop the isAfterInlining special case. To reproduce the problem, just
73+
// change the condition from `isAfterInlining` to `false`.
74+
typed(tree.expr)
75+
else
76+
//println(i"typing $tree, ${tree.expr.typeOpt}, $pt1, ${ctx.mode is Mode.Pattern}")
77+
typed(tree.expr, pt1)
6478
val result = untpd.cpy.Typed(tree)(expr1, tpt1).withType(tree.typeOpt)
6579
if ctx.mode.isExpr then result.withNotNullInfo(expr1.notNullInfo) else result
66-
}
6780

6881
override def typedTypeTree(tree: untpd.TypeTree, pt: Type)(using Context): TypeTree =
6982
promote(tree)

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

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -811,11 +811,9 @@ class Typer extends Namer
811811
val underlyingTreeTpe =
812812
if (isRepeatedParamType(tpt)) TypeTree(defn.SeqType.appliedTo(pt :: Nil))
813813
else tpt
814-
815814
val expr1 =
816-
if (isRepeatedParamType(tpt)) tree.expr.withType(defn.SeqType.appliedTo(pt :: Nil))
817-
else if (isWildcard) tree.expr.withType(tpt.tpe)
818-
else typed(tree.expr, tpt.tpe.widenSkolem)
815+
if isWildcard then tree.expr.withType(underlyingTreeTpe.tpe)
816+
else typed(tree.expr, underlyingTreeTpe.tpe.widenSkolem)
819817
assignType(cpy.Typed(tree)(expr1, tpt), underlyingTreeTpe)
820818
.withNotNullInfo(expr1.notNullInfo)
821819
}
@@ -841,8 +839,10 @@ class Typer extends Namer
841839
// We need to make sure its type is no longer nullable
842840
expr0.castToNonNullable
843841
else expr0
844-
val fromCls = if expr1.tpe.derivesFrom(defn.ArrayClass)
845-
then defn.ArrayClass else defn.SeqClass
842+
val fromCls =
843+
if expr1.tpe.derivesFrom(defn.ArrayClass)
844+
then defn.ArrayClass
845+
else defn.SeqClass
846846
val tpt1 = TypeTree(expr1.tpe.widen.translateToRepeated(fromCls)).withSpan(tree.tpt.span)
847847
assignType(cpy.Typed(tree)(expr1, tpt1), tpt1)
848848
}
@@ -1052,7 +1052,14 @@ class Typer extends Namer
10521052
val expr1 = ascribeType(expr, pt)
10531053
cpy.Block(block)(stats, expr1) withType expr1.tpe // no assignType here because avoid is redundant
10541054
case _ =>
1055-
Typed(tree, TypeTree(pt.simplified))
1055+
val target = pt.simplified
1056+
if tree.tpe <:< target then Typed(tree, TypeTree(pt.simplified))
1057+
else
1058+
// This case should not normally arise. It currently does arise in test cases
1059+
// pos/t4080b.scala and pos/i7067.scala. In that case, a type ascription is wrong
1060+
// and would not pass Ycheck. We have to use a cast instead. TODO: follow-up why
1061+
// the cases arise and eliminate them, if possible.
1062+
tree.cast(target)
10561063
}
10571064
def noLeaks(t: Tree): Boolean = escapingRefs(t, localSyms).isEmpty
10581065
if (noLeaks(tree)) tree
@@ -3690,7 +3697,7 @@ class Typer extends Namer
36903697
gadts.println(i"GADT-approximated $wtp ~~ $gadtApprox")
36913698
if pt.isMatchedBy(gadtApprox) then
36923699
gadts.println(i"Member selection healed by GADT approximation")
3693-
tpd.Typed(tree, TypeTree(gadtApprox))
3700+
tree.cast(gadtApprox)
36943701
else tree
36953702
else tree // other adaptations for selections are handled in typedSelect
36963703
case _ if ctx.mode.is(Mode.ImplicitsEnabled) && tree.tpe.isValueType =>

0 commit comments

Comments
 (0)