Skip to content

Refactor tree type parameters #16298

@odersky

Description

@odersky

Compiler version

All 3.x versions

Minimized example

The modelling of ASTs can be improved by exploiting the -Yexplicit-nulls setting, which is enabled in the dotc build.
There are the following major design criteria for AST trees, which should be kept:

  • There are untyped trees and typed trees.
  • The kind of a tree is represented by a type parameter or abstract type T.
  • For typed trees T = Type and for untyped trees T = Untyped where Untyped is either Null or Nothing.
  • Typed trees can be used where untyped trees are required, forgetting the type annotations.
  • The typeOpt method on trees returns a T, i.e. either bottom type or a Type.
  • The tpe method on trees returns a Type and will fail (ideally at compile time, but currently at runtime) if the tree is untyped.

When dotc was first designed, we fulfilled the criteria by defining type Tree like this:

  abstract class Tree[-T >: Null] ...

That made sure that typed trees Tree[Type] are a subtype of untyped trees Tree[Null], since Null was a subtype of Type. But with explicit nulls, that's no longer true. So we changed the bottom type from Null to Nothing.

Nevertheless, there's some awkwardness:

First, the tpe method on trees is variance incorrect. It is defined like this:

    final def tpe: T @uncheckedVariance = ...

Second, we can write

    val t: Type = tree.tpe

without problem even if tree is an untyped tree, since its tpe method returns Nothing, which conforms to Type.

It looks like we can get a sound system with better static checking if we model Tree instead like this:

   abstract class Tree[+T <: Type | Null]
   object untpd:
     type Tree = Tree[Type | Null]
   object tpe:
     type Tree = Tree[Type]

It's going to be a big change in the sense of number of lines changed, but it would make things clearer. So I think we should do it before going into an LTS.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions