refchecks.scala

来自「JAVA 语言的函数式编程扩展」· SCALA 代码 · 共 841 行 · 第 1/3 页

SCALA
841
字号
      // 4. Check that every defined member with an `override' modifier overrides some other member.      for (val member <- clazz.info.decls.toList)        if ((member hasFlag (OVERRIDE | ABSOVERRIDE)) &&            (clazz.info.baseClasses.tail forall {               bc => member.matchingSymbol(bc, clazz.thisType) == NoSymbol            })) {          // for (val bc <- clazz.info.baseClasses.tail) Console.println("" + bc + " has " + bc.info.decl(member.name) + ":" + bc.info.decl(member.name).tpe);//DEBUG          unit.error(member.pos, member.toString() + " overrides nothing");          member resetFlag OVERRIDE        }    }  // Basetype Checking --------------------------------------------------------    /** <ol>     *    <li> <!-- 1 -->     *      Check that later type instances in the base-type sequence     *      are subtypes of earlier type instances of the same mixin.     *    </li>     *    <li> <!-- 2 -->     *      Check that inner classes do not inherit from Annotation     *    </li>     *  </ol>     */    private def validateBaseTypes(clazz: Symbol) {      val seenTypes = new Array[Type](clazz.info.closure.length)      /** validate all base types of a class in reverse linear order. */      def validateType(tp: Type) {        val baseClass = tp.typeSymbol        if (baseClass.isClass) {          val index = clazz.info.closurePos(baseClass)          if (index >= 0) {            if (seenTypes(index) ne null) {              if (!(seenTypes(index) <:< tp)) {                unit.error(clazz.pos, "illegal inheritance;\n " + clazz +                            " inherits different type instances of " + baseClass +                            ":\n" + tp + " and " + seenTypes(index));              }            } else {              seenTypes(index) = tp              // check that inner classes do not inherit from Annotation              if (baseClass == ClassfileAnnotationClass)                if (!clazz.owner.isPackageClass)                  unit.error(clazz.pos, "inner classes cannot be classfile annotations")            }            tp.parents foreach validateType          }        }      }      validateType(clazz.tpe)    }   // Variance Checking --------------------------------------------------------    private val ContraVariance = -1    private val NoVariance = 0    private val CoVariance = 1    private val AnyVariance = 2    private val escapedPrivateLocals = new HashSet[Symbol]    val varianceValidator = new Traverser {      private def validateVariance(base: Symbol) {        def varianceString(variance: Int): String =          if (variance == 1) "covariant"          else if (variance == -1) "contravariant"          else "invariant";        def relativeVariance(tvar: Symbol): Int = {          val clazz = tvar.owner          var sym = base          var state = CoVariance          while (sym != clazz && state != AnyVariance) {            //Console.println("flip: " + sym + " " + sym.isParameter());//DEBUG            if ((sym hasFlag PARAM) && !sym.owner.isConstructor && !sym.owner.isCaseApplyOrUnapply &&                !(tvar.isTypeParameterOrSkolem && sym.isTypeParameterOrSkolem &&                  tvar.owner == sym.owner)) state = -state;            else if (!sym.owner.isClass ||                      ((sym.isPrivateLocal || sym.isProtectedLocal) && !(escapedPrivateLocals contains sym)))              state = AnyVariance            else if (sym.isAliasType)               state = NoVariance            sym = sym.owner          }          state        }        def validateVariance(tp: Type, variance: Int): Unit = tp match {          case ErrorType => ;          case WildcardType => ;          case NoType => ;          case NoPrefix => ;          case ThisType(_) => ;          case ConstantType(_) => ;          case DeBruijnIndex(_, _) => ;          case SingleType(pre, sym) =>            validateVariance(pre, variance)          case TypeRef(pre, sym, args) =>            if (sym.variance != NoVariance) {              val v = relativeVariance(sym);              if (v != AnyVariance && sym.variance != v * variance) {                //Console.println("relativeVariance(" + base + "," + sym + ") = " + v);//DEBUG                unit.error(base.pos,                           varianceString(sym.variance) + " " + sym +                            " occurs in " + varianceString(v * variance) +                            " position in type " + base.info + " of " + base);              }            }            validateVariance(pre, variance)            validateVarianceArgs(args, variance, sym.typeParams) //@M for higher-kinded typeref, args.isEmpty            // However, these args respect variances by construction anyway             // -- the interesting case is in type application, see checkKindBounds in Infer          case ClassInfoType(parents, decls, symbol) =>            validateVariances(parents, variance)          case RefinedType(parents, decls) =>            validateVariances(parents, variance)          case TypeBounds(lo, hi) =>            validateVariance(lo, -variance)            validateVariance(hi, variance)          case MethodType(formals, result) =>            validateVariance(result, variance)          case PolyType(tparams, result) =>            // type parameters will be validated separately, because they are defined explicitly.            validateVariance(result, variance)          case ExistentialType(tparams, result) =>            validateVariances(tparams map (_.info), variance)            validateVariance(result, variance)          case AnnotatedType(attribs, tp, selfsym) =>            validateVariance(tp, variance)        }        def validateVariances(tps: List[Type], variance: Int) {          tps foreach (tp => validateVariance(tp, variance))        }        def validateVarianceArgs(tps: List[Type], variance: Int, tparams: List[Symbol]) {          (tps zip tparams) foreach {            case (tp, tparam) => validateVariance(tp, variance * tparam.variance)          }        }        validateVariance(base.info, CoVariance)      }      override def traverse(tree: Tree) {        tree match {          case ClassDef(_, _, _, _) | TypeDef(_, _, _, _) =>            validateVariance(tree.symbol)            super.traverse(tree)          // ModuleDefs need not be considered because they have been eliminated already          case ValDef(_, _, _, _) =>            validateVariance(tree.symbol)          case DefDef(_, _, tparams, vparamss, tpt, rhs) =>            validateVariance(tree.symbol)            traverseTrees(tparams); traverseTreess(vparamss)          case Template(_, _, _) =>            super.traverse(tree)          case _ =>        }      }    }// Forward reference checking ---------------------------------------------------    class LevelInfo(val outer: LevelInfo) {      val scope: Scope = if (outer eq null) newScope else newScope(outer.scope)      var maxindex: Int = Math.MIN_INT      var refpos: Position = _      var refsym: Symbol = _    }    private var currentLevel: LevelInfo = null    private val symIndex = new HashMap[Symbol, Int]    private def pushLevel() {      currentLevel = new LevelInfo(currentLevel)    }    private def popLevel() {      currentLevel = currentLevel.outer    }    private def enterSyms(stats: List[Tree]) {      var index = -1      for (val stat <- stats) {         index = index + 1;         stat match {          case ClassDef(_, _, _, _) | DefDef(_, _, _, _, _, _) | ModuleDef(_, _, _) | ValDef(_, _, _, _) =>            assert(stat.symbol != NoSymbol, stat);//debug            if (stat.symbol.isLocal) {              currentLevel.scope.enter(newScopeEntry(stat.symbol, currentLevel.scope));              symIndex(stat.symbol) = index;            }          case _ =>        }      }    }    private def enterReference(pos: Position, sym: Symbol) {      if (sym.isLocal) {        val e = currentLevel.scope.lookupEntry(sym.name)        if ((e ne null) && sym == e.sym) {          var l = currentLevel          while (l.scope != e.owner) l = l.outer;          val symindex = symIndex(sym)          if (l.maxindex < symindex) {            l.refpos = pos            l.refsym = sym            l.maxindex = symindex          }        }      }    }// Comparison checking -------------------------------------------------------    object normalizeAll extends TypeMap {      def apply(tp: Type) = mapOver(tp).normalize    }        def checkSensible(pos: Position, fn: Tree, args: List[Tree]) = fn match {      case Select(qual, name) if (args.length == 1) =>        def isNew(tree: Tree) = tree match {          case Function(_, _)              | Apply(Select(New(_), nme.CONSTRUCTOR), _) => true          case _ => false        }        name match {          case nme.EQ | nme.NE | nme.LT | nme.GT | nme.LE | nme.GE =>            def underlyingClass(tp: Type): Symbol = {              var sym = tp.widen.typeSymbol              while (sym.isAbstractType)                sym = sym.info.bounds.hi.widen.typeSymbol              sym            }            val formal = underlyingClass(fn.tpe.paramTypes.head)            val actual = underlyingClass(args.head.tpe)            val receiver = underlyingClass(qual.tpe)            def nonSensibleWarning(what: String, alwaysEqual: Boolean) =               unit.warning(pos, "comparing "+what+" using `"+name.decode+"' will always yield "+                           (alwaysEqual == (name == nme.EQ || name == nme.LE || name == nme.GE)))            def nonSensible(pre: String, alwaysEqual: Boolean) =              nonSensibleWarning(pre+"values of types "+normalizeAll(qual.tpe.widen)+" and "+normalizeAll(args.head.tpe.widen),                                 alwaysEqual) // @MAT normalize for consistency in error message, otherwise part is normalized due to use of `typeSymbol', but the rest isn't            def hasObjectEquals = receiver.info.member(nme.equals_) == Object_equals            if (formal == UnitClass && actual == UnitClass)              nonSensible("", true)            else if ((receiver == BooleanClass || receiver == UnitClass) &&                      !(receiver isSubClass actual))              nonSensible("", false)            else if (isNumericValueClass(receiver) &&                     !isNumericValueClass(actual) &&                     !(forMSIL || forCLDC|| (actual isSubClass BoxedNumberClass)) &&                     !(receiver isSubClass actual))              nonSensible("", false)            else if ((receiver hasFlag FINAL) && hasObjectEquals && !isValueClass(receiver) &&                      !(receiver isSubClass actual) && receiver != AllRefClass && actual != AllRefClass &&                     (name == nme.EQ || name == nme.LE))              nonSensible("non-null ", false)            else if ((isNew(qual) || isNew(args.head)) && hasObjectEquals)              nonSensibleWarning("a fresh object", false)          case _ =>        }      case _ =>    }// Transformation ------------------------------------------------------------    /* Convert a reference to a case factory of type `tpe' to a new of the class it produces. */    def toConstructor(pos: Position, tpe: Type): Tree = {      var rtpe = tpe.finalResultType      assert(rtpe.typeSymbol hasFlag CASE, tpe);      localTyper.typedOperator {        atPos(pos) {          Select(New(TypeTree(rtpe)), rtpe.typeSymbol.primaryConstructor)        }      }    }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?