aboutsummaryrefslogblamecommitdiff
path: root/compiler/src/dotty/tools/dotc/ast/CheckTrees.scala.disabled
blob: 255619f35d180d6f4fc98c0719e0ca45feb34dc5 (plain) (tree)
1
2
3
4
5
6
7
8
9






                                                                           
 
                                               

                   
              
 

                                                                                          
                                                                                  



                                  
                                                                                      
                                    
                                                                   

                                                     






                                       
                                                           
                                                  
                                                                
                                               
                                                                          




                                                        
                                                                       












                                                        
                                                                 


                                      































                                                                                              
                                                                                                    










                                            
                                     
                         
                                       

                                                                     
                                             














                                                         







                                                                            
                                             




                                                          
                                                                                        


                                                      

                                    

                           
                                  




















                                                        
                                                                                     










                                                                          
                                                                                  
















                                                                     
                                                         






                                                   
                                                   

                                     
                                          

                               
                                             
                                                 
                                      
                                            

                                    
                                                                  




















                                                           
                                    
                                                                           
                                                     









                                                                
                     


   
package dotty.tools
package dotc
package ast

import core._
import util.Positions._, Types._, Contexts._, Constants._, Names._, Flags._
import SymDenotations._, Symbols._, StdNames._, Annotations._, Trees._

// TODO: revise, integrate in a checking phase.
object CheckTrees {

  import tpd._

  def check(p: Boolean, msg: => String = "")(implicit ctx: Context): Unit = assert(p, msg)

  def checkTypeArg(arg: Tree, bounds: TypeBounds)(implicit ctx: Context): Unit = {
    check(arg.isValueType)
    check(bounds contains arg.tpe)
  }

  def escapingRefs(block: Block)(implicit ctx: Context): collection.Set[NamedType] = {
    var hoisted: Set[Symbol] = Set()
    lazy val locals = ctx.typeAssigner.localSyms(block.stats).toSet
    def isLocal(sym: Symbol): Boolean =
      (locals contains sym) && !isHoistableClass(sym)
    def isHoistableClass(sym: Symbol) =
      sym.isClass && {
        (hoisted contains sym) || {
          hoisted += sym
          !classLeaks(sym.asClass)
        }
      }
    def leakingTypes(tp: Type): collection.Set[NamedType] =
      tp namedPartsWith (tp => isLocal(tp.symbol))
    def typeLeaks(tp: Type): Boolean = leakingTypes(tp).nonEmpty
    def classLeaks(sym: ClassSymbol): Boolean =
      (ctx.owner is Method) || // can't hoist classes out of method bodies
      (sym.info.parents exists typeLeaks) ||
      (sym.decls.toList exists (t => typeLeaks(t.info)))
    leakingTypes(block.tpe)
  }

  def checkType(tree: Tree)(implicit ctx: Context): Unit = tree match {
    case Ident(name) =>
    case Select(qualifier, name) =>
      check(qualifier.isValue)
      check(qualifier.tpe =:= tree.tpe.normalizedPrefix)
      val denot = qualifier.tpe.member(name)
      check(denot.exists)
      check(denot.hasAltWith(_.symbol == tree.symbol))
    case This(cls) =>
    case Super(qual, mixin) =>
      check(qual.isValue)
      val cls = qual.tpe.typeSymbol
      check(cls.isClass)
    case Apply(fn, args) =>
      def checkArg(arg: Tree, name: Name, formal: Type): Unit = {
        arg match {
          case NamedArg(argName, _) =>
            check(argName == name)
          case _ =>
            check(arg.isValue)
        }
        check(arg.tpe <:< formal)
      }
      val MethodType(paramNames, paramTypes) = fn.tpe.widen // checked already at construction
      (args, paramNames, paramTypes).zipped foreach checkArg
    case TypeApply(fn, args) =>
      val pt @ PolyType(_) = fn.tpe.widen // checked already at construction
      (args, pt.instantiateBounds(args map (_.tpe))).zipped foreach checkTypeArg
    case Literal(const: Constant) =>
    case New(tpt) =>
      check(tpt.isValueType)
      val cls = tpt.tpe.typeSymbol
      check(cls.isClass)
      check(!(cls is AbstractOrTrait))
    case Pair(left, right) =>
      check(left.isValue)
      check(right.isValue)
    case Typed(expr, tpt) =>
      check(tpt.isValueType)
      expr.tpe.widen match {
        case tp: MethodType =>
          val cls = tpt.tpe.typeSymbol
          check(cls.isClass)
          check((cls is Trait) ||
                cls.primaryConstructor.info.paramTypess.flatten.isEmpty)
          val absMembers = tpt.tpe.abstractTermMembers
          check(absMembers.size == 1)
          check(tp <:< absMembers.head.info)
        case _ =>
          check(expr.isValueOrPattern)
          check(expr.tpe <:< tpt.tpe.translateParameterized(defn.RepeatedParamClass, defn.SeqClass))
      }
    case NamedArg(name, arg) =>
    case Assign(lhs, rhs) =>
      check(lhs.isValue); check(rhs.isValue)
      lhs.tpe match {
        case ltpe: TermRef =>
          check(ltpe.symbol is Mutable)
        case _ =>
          check(false)
      }
      check(rhs.tpe <:< lhs.tpe.widen)
    case tree @ Block(stats, expr) =>
      check(expr.isValue)
      check(escapingRefs(tree).isEmpty)
    case If(cond, thenp, elsep) =>
      check(cond.isValue); check(thenp.isValue); check(elsep.isValue)
      check(cond.tpe isRef defn.BooleanClass)
    case Closure(env, meth, target) =>
   	  meth.tpe.widen match {
   	    case mt @ MethodType(_, paramTypes) =>
   	      if (target.isEmpty) {
   	        check(env.length < paramTypes.length)
   	        for ((arg, formal) <- env zip paramTypes)
   	          check(arg.tpe <:< formal)
   	      }
   	      else
   	        // env is stored in class, not method
   	        target.tpe match {
   	          case SAMType(targetMeth) =>
   	            check(mt <:< targetMeth.info)
   	        }
   	  }
    case Match(selector, cases) =>
      check(selector.isValue)
      // are any checks that relate selector and patterns desirable?
    case CaseDef(pat, guard, body) =>
      check(pat.isValueOrPattern); check(guard.isValue); check(body.isValue)
      check(guard.tpe.derivesFrom(defn.BooleanClass))
    case Return(expr, from) =>
      check(expr.isValue); check(from.isTerm)
      check(from.tpe.termSymbol.isRealMethod)
    case Try(block, handler, finalizer) =>
      check(block.isTerm)
      check(finalizer.isTerm)
      check(handler.isTerm)
      check(handler.tpe derivesFrom defn.FunctionClass(1))
      check(handler.tpe.baseArgInfos(defn.FunctionClass(1)).head <:< defn.ThrowableType)
    case Throw(expr) =>
      check(expr.isValue)
      check(expr.tpe.derivesFrom(defn.ThrowableClass))
    case SeqLiteral(elems) =>
      val elemtp = tree.tpe.elemType
      for (elem <- elems) {
        check(elem.isValue)
        check(elem.tpe <:< elemtp)
      }
    case TypeTree(original) =>
      if (!original.isEmpty) {
        check(original.isValueType)
        check(original.tpe == tree.tpe)
      }
    case SingletonTypeTree(ref) =>
      check(ref.isValue)
      check(ref.symbol.isStable)
    case SelectFromTypeTree(qualifier, name) =>
      check(qualifier.isValueType)
      check(qualifier.tpe =:= tree.tpe.normalizedPrefix)
      val denot = qualifier.tpe.member(name)
      check(denot.exists)
      check(denot.symbol == tree.symbol)
    case AndTypeTree(left, right) =>
      check(left.isValueType); check(right.isValueType)
    case OrTypeTree(left, right) =>
      check(left.isValueType); check(right.isValueType)
    case RefinedTypeTree(tpt, refinements) =>
      check(tpt.isValueType)
      def checkRefinements(forbidden: Set[Symbol], rs: List[Tree]): Unit = rs match {
        case r :: rs1 =>
          val rsym = r.symbol
          check(rsym.isTerm || rsym.isAbstractOrAliasType)
          if (rsym.isAbstractType) check(tpt.tpe.member(rsym.name).exists)
          check(rsym.info forallParts {
            case nt: NamedType => !(forbidden contains nt.symbol)
            case _ => true
          })
          checkRefinements(forbidden - rsym, rs1)
        case nil =>
      }
      checkRefinements(ctx.typeAssigner.localSyms(refinements).toSet, refinements)
    case AppliedTypeTree(tpt, args) =>
      check(tpt.isValueType)
      val tparams = tpt.tpe.typeParams
      check(sameLength(tparams, args))
      (args, tparams map (_.info.bounds)).zipped foreach checkTypeArg
    case TypeBoundsTree(lo, hi) =>
      check(lo.isValueType); check(hi.isValueType)
      check(lo.tpe <:< hi.tpe)
    case Bind(sym, body) =>
      check(body.isValueOrPattern)
      check(!(tree.symbol is Method))
      body match {
        case Ident(nme.WILDCARD) =>
        case _ => check(body.tpe.widen =:= tree.symbol.info)
      }
    case Alternative(alts) =>
      for (alt <- alts) check(alt.isValueOrPattern)
    case UnApply(fun, implicits, args) => // todo: review
      check(fun.isTerm)
      for (arg <- args) check(arg.isValueOrPattern)
      val funtpe @ MethodType(_, _) = fun.tpe.widen
      fun.symbol.name match { // check arg arity
        case nme.unapplySeq =>
          // args need to be wrapped in (...: _*)
          check(args.length == 1)
          check(args.head.isInstanceOf[SeqLiteral])
        case nme.unapply =>
          val rtp = funtpe.resultType
          if (rtp isRef defn.BooleanClass)
            check(args.isEmpty)
          else {
            check(rtp isRef defn.OptionClass)
            val normArgs = rtp.argTypesHi match {
              case optionArg :: Nil =>
                optionArg.argTypesHi match {
                  case Nil =>
                    optionArg :: Nil
                  case tupleArgs if defn.isTupleType(optionArg) =>
                    tupleArgs
                }
              case _ =>
                check(false)
                Nil
            }
            check(sameLength(normArgs, args))
          }
      }
    case ValDef(mods, name, tpt, rhs) =>
      check(!(tree.symbol is Method))
      if (!rhs.isEmpty) {
        check(rhs.isValue)
        check(rhs.tpe <:< tpt.tpe)
      }
    case DefDef(mods, name, tparams, vparamss, tpt, rhs) =>
      check(tree.symbol is Method)
      if (!rhs.isEmpty) {
        check(rhs.isValue)
        check(rhs.tpe <:< tpt.tpe)
      }
    case TypeDef(mods, name, tpt) =>
      check(tpt.isInstanceOf[Template] || tpt.tpe.isInstanceOf[TypeBounds])
    case Template(constr, parents, selfType, body) =>
    case Import(expr, selectors) =>
      check(expr.isValue)
      check(expr.tpe.termSymbol.isStable)
    case PackageDef(pid, stats) =>
      check(pid.isTerm)
      check(pid.symbol is Package)
    case Annotated(annot, arg) =>
      check(annot.isInstantiation)
      check(annot.symbol.owner.isSubClass(defn.AnnotationClass))
      check(arg.isValueType || arg.isValue)
    case EmptyTree =>
  }
}