Skip to content

Clean up kindedness tests #4360

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 4 commits into from
May 7, 2018
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
6 changes: 3 additions & 3 deletions compiler/src/dotty/tools/dotc/core/TypeApplications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -210,9 +210,9 @@ class TypeApplications(val self: Type) extends AnyVal {
/** Is self type bounded by a type lambda or AnyKind? */
def isLambdaSub(implicit ctx: Context): Boolean = hkResult.exists

/** Is self type of kind != "*"? */
def hasHigherKind(implicit ctx: Context): Boolean =
typeParams.nonEmpty || self.isRef(defn.AnyKindClass)
/** Is self type of kind "*"? */
def hasSimpleKind(implicit ctx: Context): Boolean =
typeParams.isEmpty && !self.hasAnyKind

/** If self type is higher-kinded, its result type, otherwise NoType.
* Note: The hkResult of an any-kinded type is again AnyKind.
Expand Down
14 changes: 14 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,20 @@ object Types {
/** Is this type a (possibly aliased) singleton type? */
def isSingleton(implicit ctx: Context) = dealias.isInstanceOf[SingletonType]

/** Is this type of kind `AnyKind`? */
def hasAnyKind(implicit ctx: Context): Boolean = {
@tailrec def loop(tp: Type): Boolean = tp match {
case tp: TypeRef =>
val sym = tp.symbol
if (sym.isClass) sym == defn.AnyKindClass else loop(tp.superType)
case tp: TypeProxy =>
loop(tp.underlying)
case _ =>
false
}
loop(this)
}

/** Is this type guaranteed not to have `null` as a value? */
final def isNotNull(implicit ctx: Context): Boolean = this match {
case tp: ConstantType => tp.value.value != null
Expand Down
5 changes: 4 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,10 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
}
case tree: TypeApply =>
val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree)
Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
if (fn.symbol != defn.ChildAnnot.primaryConstructor) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of special-casing Child, the compiler could be changed to always use it with fully-applied types with wildcards, e.g. Child[Cons[_]]

// Make an exception for ChildAnnot, which should really have AnyKind bounds
Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType])
}
fn match {
case sel: Select =>
val args1 = transform(args)
Expand Down
5 changes: 3 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Checking.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,10 @@ object Checking {
*/
def checkBounds(args: List[tpd.Tree], boundss: List[TypeBounds], instantiate: (Type, List[Type]) => Type)(implicit ctx: Context): Unit = {
(args, boundss).zipped.foreach { (arg, bound) =>
if (!bound.isLambdaSub && arg.tpe.isLambdaSub)
if (!bound.isLambdaSub && !arg.tpe.hasSimpleKind) {
// see MissingTypeParameterFor
ctx.error(ex"missing type parameter(s) for $arg", arg.pos)
}
}
for ((arg, which, bound) <- ctx.boundsViolations(args, boundss, instantiate))
ctx.error(
Expand Down Expand Up @@ -704,7 +705,7 @@ trait Checking {

/** Check that `tpt` does not define a higher-kinded type */
def checkSimpleKinded(tpt: Tree)(implicit ctx: Context): Tree =
if (tpt.tpe.isLambdaSub && !ctx.compilationUnit.isJava) {
if (!tpt.tpe.hasSimpleKind && !ctx.compilationUnit.isJava) {
// be more lenient with missing type params in Java,
// needed to make pos/java-interop/t1196 work.
errorTree(tpt, MissingTypeParameterFor(tpt.tpe))
Expand Down
4 changes: 3 additions & 1 deletion compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,9 @@ trait TypeAssigner {
*/
def accessibleSelectionType(tree: untpd.RefTree, qual1: Tree)(implicit ctx: Context): Type = {
var qualType = qual1.tpe.widenIfUnstable
if (qualType.isLambdaSub) qualType = errorType(em"$qualType takes type parameters", qual1.pos)
if (!qualType.hasSimpleKind && tree.name != nme.CONSTRUCTOR)
// constructors are selected on typeconstructor, type arguments are passed afterwards
qualType = errorType(em"$qualType takes type parameters", qual1.pos)
else if (!qualType.isInstanceOf[TermType]) qualType = errorType(em"$qualType is illegal as a selection prefix", qual1.pos)
val ownType = selectionType(qualType, tree.name, tree.pos)
ensureAccessible(ownType, qual1.isInstanceOf[Super], tree.pos)
Expand Down
1 change: 1 addition & 0 deletions library/src/scala/annotation/internal/Child.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ import scala.annotation.Annotation
* Then the class symbol `A` would carry the annotations
* `@Child[Bref] @Child[Cref]` where `Bref`, `Cref` are TypeRefs
* referring to the class symbols of `B` and `C`
* TODO: This should be `Child[T <: AnyKind]`
*/
class Child[T] extends Annotation