Skip to content

Commit 5d8b977

Browse files
committed
Fix cyclic complete and inference
1 parent 969a224 commit 5d8b977

File tree

6 files changed

+36
-17
lines changed

6 files changed

+36
-17
lines changed

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import collection.{immutable, mutable}
1414
import util.{Property, SourceFile, NoSource}
1515
import NameKinds.{TempResultName, OuterSelectName}
1616
import typer.ConstFold
17+
import typer.Nullables
1718

1819
import scala.annotation.tailrec
1920
import scala.io.Codec
@@ -935,7 +936,10 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
935936

936937
/** The current tree applied to given type argument list: `tree[targs(0), ..., targs(targs.length - 1)]` */
937938
def appliedToTypeTrees(targs: List[Tree])(using Context): Tree =
938-
if (targs.isEmpty) tree else TypeApply(tree, targs)
939+
if targs.isEmpty then tree else
940+
val app = TypeApply(tree, targs)
941+
app.putAttachment(Nullables.UnsafeNullsKey, config.Feature.unsafeNullsEnabled)
942+
app
939943

940944
/** Apply to `()` unless tree's widened type is parameterless */
941945
def ensureApplied(using Context): Tree =

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,13 @@ object Types {
218218
case tp: TypeRef => defn.topClasses.contains(tp.symbol)
219219
case _ => false
220220

221+
/** Is this type exactly Null (no vars, aliases, refinements etc allowed)? */
222+
def isExactlyNull(using Context): Boolean = this match {
223+
case tp: TypeRef =>
224+
tp.name == tpnme.Null && (tp.symbol eq defn.NullClass)
225+
case _ => false
226+
}
227+
221228
/** Is this type exactly Nothing (no vars, aliases, refinements etc allowed)? */
222229
def isExactlyNothing(using Context): Boolean = this match {
223230
case tp: TypeRef =>

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

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import core._
77
import dotty.tools.dotc.typer.Checking
88
import dotty.tools.dotc.typer.Inliner
99
import dotty.tools.dotc.typer.VarianceChecker
10+
import dotty.tools.dotc.typer.Nullables
1011
import Types._, Contexts._, Names._, Flags._, DenotTransformers._, Phases._
1112
import SymDenotations._, StdNames._, Annotations._, Trees._, Scopes._
1213
import Decorators._
@@ -305,7 +306,11 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
305306
args.foreach(checkInferredWellFormed)
306307
if (fn.symbol != defn.ChildAnnot.primaryConstructor)
307308
// Make an exception for ChildAnnot, which should really have AnyKind bounds
308-
Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
309+
val checkCtx = if tree.attachmentOrElse(Nullables.UnsafeNullsKey, false) then
310+
ctx.addMode(Mode.UnsafeNullsSubType)
311+
else
312+
ctx
313+
Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])(using checkCtx)
309314
fn match {
310315
case sel: Select =>
311316
val args1 = transform(args)
@@ -365,7 +370,11 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
365370
else if (tree.tpt.symbol == defn.orType)
366371
() // nothing to do
367372
else
368-
Checking.checkAppliedType(tree)
373+
val checkCtx = if tree.attachmentOrElse(Nullables.UnsafeNullsKey, false) then
374+
ctx.addMode(Mode.UnsafeNullsSubType)
375+
else
376+
ctx
377+
Checking.checkAppliedType(tree)(using checkCtx)
369378
super.transform(tree)
370379
case SingletonTypeTree(ref) =>
371380
Checking.checkRealizable(ref.tpe, ref.srcPos)

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1059,7 +1059,7 @@ trait Applications extends Compatibility {
10591059
val isNamed = hasNamedArg(tree.args)
10601060
val typedArgs = if (isNamed) typedNamedArgs(tree.args) else tree.args.mapconserve(typedType(_))
10611061
record("typedTypeApply")
1062-
typedExpr(tree.fun, PolyProto(typedArgs, pt)) match {
1062+
val app = typedExpr(tree.fun, PolyProto(typedArgs, pt)) match {
10631063
case IntegratedTypeArgs(app) =>
10641064
app
10651065
case _: TypeApply if !ctx.isAfterTyper =>
@@ -1082,6 +1082,8 @@ trait Applications extends Compatibility {
10821082
if (typedFn.tpe eq TryDynamicCallType) tryDynamicTypeApply()
10831083
else assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)
10841084
}
1085+
app.putAttachment(Nullables.UnsafeNullsKey, config.Feature.unsafeNullsEnabled)
1086+
app
10851087
}
10861088

10871089
/** Rewrite `new Array[T](....)` if T is an unbounded generic to calls to newGenericArray.

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

Lines changed: 7 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,24 @@ object Nullables:
2222

2323
private def needNullifyHi(lo: Type, hi: Type)(using Context): Boolean =
2424
ctx.explicitNulls
25-
&& lo.isBottomTypeAfterErasure
26-
&& !hi.isAny
27-
&& !hi.isBottomTypeAfterErasure
25+
&& lo.isExactlyNull
2826
&& hi.isValueType
29-
&& hi.isNullableAfterErasure
3027

3128
def createNullableTypeBounds(lo: Type, hi: Type)(using Context): TypeBounds =
32-
TypeBounds(lo,
33-
if needNullifyHi(lo, hi)
34-
then OrNull(hi)
35-
else hi)
29+
val newHi = if needNullifyHi(lo, hi) then OrType(hi, defn.NullType, soft = false) else hi
30+
TypeBounds(lo, newHi)
3631

3732
def createNullableTypeBoundsTree(lo: Tree, hi: Tree, alias: Tree = EmptyTree)(using Context): TypeBoundsTree =
3833
val hiTpe = hi.typeOpt
39-
TypeBoundsTree(lo,
40-
if needNullifyHi(lo.typeOpt, hiTpe)
41-
then TypeTree(OrNull(hiTpe))
42-
else hi, alias)
34+
val newHi = if needNullifyHi(lo.typeOpt, hiTpe) then TypeTree(OrType(hiTpe, defn.NullType, soft = false)) else hi
35+
TypeBoundsTree(lo, newHi, alias)
4336

4437
inline def useUnsafeNullsSubTypeIf[T](cond: Boolean)(inline op: Context ?=> T)(using Context): T =
4538
val c = if cond then ctx.addMode(Mode.UnsafeNullsSubType) else ctx
4639
op(using c)
4740

41+
val UnsafeNullsKey = Property.StickyKey[Boolean]
42+
4843
/** A set of val or var references that are known to be not null, plus a set of
4944
* variable references that are not known (anymore) to be not null
5045
*/

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1830,7 +1830,9 @@ class Typer extends Namer
18301830
checkedArgs = List(TypeTree(elemtp).withSpan(arg.span))
18311831
case _ =>
18321832
}
1833-
assignType(cpy.AppliedTypeTree(tree)(tpt1, checkedArgs), tpt1, checkedArgs)
1833+
val appTpTree =assignType(cpy.AppliedTypeTree(tree)(tpt1, checkedArgs), tpt1, checkedArgs)
1834+
appTpTree.putAttachment(Nullables.UnsafeNullsKey, config.Feature.unsafeNullsEnabled)
1835+
appTpTree
18341836
}
18351837
}
18361838

0 commit comments

Comments
 (0)