Skip to content

Commit e675e77

Browse files
committed
improve any.IsConst to be evaluated only if its argument is concrete and known
1 parent 9e0413d commit e675e77

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

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

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4240,9 +4240,36 @@ object Types {
42404240
case _ => None
42414241
}
42424242

4243-
def isConst(tp : Type) : Option[Type] = tp.fixForEvaluation match {
4244-
case ConstantType(_) => Some(ConstantType(Constant(true)))
4245-
case _ => Some(ConstantType(Constant(false)))
4243+
val opsSet = Set(
4244+
defn.CompiletimeOpsAnyModuleClass,
4245+
defn.CompiletimeOpsIntModuleClass,
4246+
defn.CompiletimeOpsLongModuleClass,
4247+
defn.CompiletimeOpsFloatModuleClass,
4248+
defn.CompiletimeOpsBooleanModuleClass,
4249+
defn.CompiletimeOpsStringModuleClass
4250+
)
4251+
4252+
//Returns Some(true) if the type is a constant.
4253+
//Returns Some(false) if the type is not a constant.
4254+
//Returns None if there is not enough information to determine if the type is a constant.
4255+
//The type is a constant if it is a constant type or a type operation composition of constant types.
4256+
//If we get a type reference for an argument, then the result is not yet known.
4257+
def isConst(tp : Type) : Option[Boolean] = tp.dealias match {
4258+
//known to be constant
4259+
case ConstantType(_) => Some(true)
4260+
//currently not a concrete known type
4261+
case TypeRef(NoPrefix,_) => None
4262+
//currently not a concrete known type
4263+
case _ : TypeParamRef => None
4264+
//constant if the term is constant
4265+
case t : TermRef => isConst(t.underlying)
4266+
//an operation type => recursively check all argument compositions
4267+
case applied : AppliedType if opsSet.contains(applied.typeSymbol.owner) =>
4268+
val argsConst = applied.args.map(isConst)
4269+
if (argsConst.exists(_.isEmpty)) None
4270+
else Some(argsConst.forall(_.get))
4271+
//all other types are considered not to be constant
4272+
case _ => Some(false)
42464273
}
42474274

42484275
def expectArgsNum(expectedNum : Int) : Unit =
@@ -4300,7 +4327,7 @@ object Types {
43004327
case tpnme.Equals => constantFold2(constValue, _ == _)
43014328
case tpnme.NotEquals => constantFold2(constValue, _ != _)
43024329
case tpnme.ToString => constantFold1(constValue, _.toString)
4303-
case tpnme.IsConst => isConst(args.head)
4330+
case tpnme.IsConst => isConst(args.head).map(b => ConstantType(Constant(b)))
43044331
case _ => None
43054332
} else if (owner == defn.CompiletimeOpsIntModuleClass) name match {
43064333
case tpnme.Abs => constantFold1(intValue, _.abs)

tests/neg/singleton-ops-any.scala

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,11 @@ object Test {
3030
final val two = 2
3131
val t47 : IsConst[two.type] = true
3232
val t48: IsConst[Any] = true // error
33-
33+
def isConst[X] : IsConst[X] = ???
34+
val t49 : true = isConst[1]
35+
val t50 : false = isConst[one.type]
36+
def isConst2[X <: Int, Y <: Int] : IsConst[X == Y] = ???
37+
val t51 : true = isConst2[1, 1]
38+
val t52 : false = isConst2[1, one.type]
39+
val t53 : true = isConst2[1, two.type]
3440
}

0 commit comments

Comments
 (0)