From 679444e28386207f255ed0e0aa3994e8b9dca73b Mon Sep 17 00:00:00 2001 From: Fengyun Liu Date: Sat, 8 Oct 2022 12:56:04 +0200 Subject: [PATCH] Remove obsolete code --- .../tools/dotc/transform/init/Checker.scala | 2 - .../transform/init/ParamOverridingCheck.scala | 343 ------------------ tests/init/neg/class-param.check | 4 - tests/init/neg/class-param.scala | 7 - tests/init/neg/i15764.scala | 7 - tests/init/neg/i15764b.scala | 7 - tests/init/neg/i15764c.scala | 5 - tests/init/neg/i15764d.scala | 9 - tests/init/neg/i15764e.scala | 18 - tests/init/pos/i15764.scala | 6 - tests/init/pos/i15764b.scala | 8 - tests/init/pos/i15764c.scala | 9 - tests/init/pos/i15764d.scala | 13 - tests/init/pos/i15764e.scala | 3 - 14 files changed, 441 deletions(-) delete mode 100644 compiler/src/dotty/tools/dotc/transform/init/ParamOverridingCheck.scala delete mode 100644 tests/init/neg/class-param.check delete mode 100644 tests/init/neg/class-param.scala delete mode 100644 tests/init/neg/i15764.scala delete mode 100644 tests/init/neg/i15764b.scala delete mode 100644 tests/init/neg/i15764c.scala delete mode 100644 tests/init/neg/i15764d.scala delete mode 100644 tests/init/neg/i15764e.scala delete mode 100644 tests/init/pos/i15764.scala delete mode 100644 tests/init/pos/i15764b.scala delete mode 100644 tests/init/pos/i15764c.scala delete mode 100644 tests/init/pos/i15764d.scala delete mode 100644 tests/init/pos/i15764e.scala diff --git a/compiler/src/dotty/tools/dotc/transform/init/Checker.scala b/compiler/src/dotty/tools/dotc/transform/init/Checker.scala index 23df0808cfb1..1efb3c88149e 100644 --- a/compiler/src/dotty/tools/dotc/transform/init/Checker.scala +++ b/compiler/src/dotty/tools/dotc/transform/init/Checker.scala @@ -36,7 +36,6 @@ class Checker extends Phase: units.foreach { unit => traverser.traverse(unit.tpdTree) } val classes = traverser.getClasses() - ParamOverridingCheck.checkClasses(classes)(using checkCtx) Semantic.checkClasses(classes)(using checkCtx) units @@ -68,7 +67,6 @@ class Checker extends Phase: } end InitTreeTraverser - object Checker: val name: String = "initChecker" val description: String = "check initialization of objects" diff --git a/compiler/src/dotty/tools/dotc/transform/init/ParamOverridingCheck.scala b/compiler/src/dotty/tools/dotc/transform/init/ParamOverridingCheck.scala deleted file mode 100644 index 6e9bd6144a7a..000000000000 --- a/compiler/src/dotty/tools/dotc/transform/init/ParamOverridingCheck.scala +++ /dev/null @@ -1,343 +0,0 @@ -package dotty.tools.dotc -package transform -package init - -import core.* -import Contexts.* -import Symbols.* -import Types.* -import StdNames.* -import NameKinds.OuterSelectName -import util.Property - -import ast.tpd.* -import config.Printers.init as printer -import reporting.trace as log - -import Semantic.Arg -import Semantic.NewExpr -import Semantic.Call -import Semantic.hasSource - -import scala.collection.mutable -import scala.annotation.tailrec - -/** - * Check overriding of class parameters - * - * This check issues a warning if the use of a class pamameter in the primary - * constructor potentially has different semantics from its use in methods. - * The subtle semantic difference is demonstrated by the following exmpale: - * - * class B(val y: Int): - * println(y) // 10 - * foo() - * def foo() = println(y) // 20 - * - * class C(override val y: Int) extends B(10) - * - * new C(20) - * - * A well-formed program should not depend on such subtle semantic differences. - * Therefore, we detect and warn such subtle semantic differences in code. - * - * This check depends on loading TASTY from libraries. It can be enabled with - * the compiler option `-Ysafe-init`. - */ -object ParamOverridingCheck: - type Contextual[T] = Context ?=> T - - private val IsInSuperCall = new Property.Key[Boolean] - - // ----------------------- Domain definitions -------------------------------- - - sealed abstract class Value: - val source: Tree - - /** - * A symbolic value - * - * Equality is defined as referential equality. - */ - class Skolem(val source: Tree) extends Value - - /** A reference to the object under initialization pointed by `this` */ - class ThisRef(val klass: ClassSymbol, fields: mutable.Map[Symbol, Value]) extends Value: - val source = klass.defTree - - def initField(sym: Symbol, value: Value) = - assert(!fields.contains(sym), "The " + sym + " is already initialized") - fields(sym) = value - - def field(sym: Symbol) = fields(sym) - - def fieldInitialized(sym: Symbol) = fields.contains(sym) - - // ----------------------- Domain operations --------------------------------- - - extension (value: Value) - - def select(field: Symbol, receiver: Type, needResolve: Boolean = true, source: Tree): Contextual[Value] = log("select " + field.show + ", this = " + value, printer) { - value match - case ref: ThisRef => - val target = - if needResolve && ctx.property(IsInSuperCall).isEmpty then - Semantic.resolve(ref.klass, field) - else - field - - if target.is(Flags.Lazy) then - val rhs = target.defTree.asInstanceOf[ValDef].rhs - eval(rhs, ref, target.owner.asClass) - else if target.exists then - if ref.fieldInitialized(target) then - ref.field(target) - else - Skolem(source) - else - if ref.klass.isSubClass(receiver.widenSingleton.classSymbol) then - report.error("[Internal error] Unexpected resolution failure: ThisRef.klass = " + ref.klass.show + ", field = " + field.show, source) - Skolem(source) - else - // This is possible due to incorrect type cast. - // See tests/init/pos/Type.scala - Skolem(source) - - case _ => - Skolem(source) - } - - extension (thisV: ThisRef) - def callConstructor(ctor: Symbol, args: List[Value]): Contextual[Unit] = log("call " + ctor.show + ", args = " + args, printer) { - // init "fake" param fields for parameters of primary and secondary constructors - def addParamsAsFields(args: List[Value], ref: ThisRef, ctorDef: DefDef) = - val params = ctorDef.termParamss.flatten.map(_.symbol) - assert(args.size == params.size, "arguments = " + args.size + ", params = " + params.size) - for (param, value) <- params.zip(args) do - ref.initField(param, value) - printer.println(param.show + " initialized with " + value) - - if ctor.hasSource && !ctor.is(Flags.JavaDefined) then - val cls = ctor.owner.enclosingClass.asClass - val ddef = ctor.defTree.asInstanceOf[DefDef] - addParamsAsFields(args, thisV, ddef) - if ctor.isPrimaryConstructor then - val tpl = cls.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template] - init(tpl, thisV, cls) - else - ddef.rhs match - case Block(Call(ref, argss) :: _, _) => - val args = evalArgs(argss.flatten, thisV, cls) - thisV.callConstructor(ref.symbol, args) - - case _ => - report.error("Unexpected rhs = " + ddef.rhs.show + " in " + cls.show, ddef.rhs) - - } - end extension - - // --------------------------------- API ------------------------------------- - - /** - * Check the specified concrete classes - */ - def checkClasses(classes: List[ClassSymbol])(using Context): Unit = - for classSym <- classes if !classSym.is(Flags.Trait) do - val thisRef = ThisRef(classSym, fields = mutable.Map.empty) - val tpl = classSym.defTree.asInstanceOf[TypeDef].rhs.asInstanceOf[Template] - for param <- tpl.constr.termParamss.flatten yield - thisRef.initField(param.symbol, new Skolem(param)) - - init(tpl, thisRef, classSym) - - // check parameter access semantics - for - klass <- classSym.parentSyms - paramSym <- klass.asClass.paramGetters - overridingClass <- (classSym :: classSym.parentSyms).filter(cls => cls != klass && cls.isSubClass(klass)) - overridingSym = paramSym.overridingSymbol(overridingClass.asClass) if overridingSym.exists - do - // println(paramSym.show + " is overridden in " + thisRef.klass) - if !overridingSym.is(Flags.ParamAccessor) then - report.warning("Overriding parameter " + paramSym.show + " in " + klass.show + " as non-parameter in " + overridingSym.owner.show, overridingSym.defTree) - else - val overridingValue = thisRef.field(overridingSym) - if thisRef.field(paramSym) != overridingValue then - // println(overridingSym.show + " in " + thisRef.klass + " = " + overridingValue) - // println(paramSym.show + " in " + klass + " = " + thisRef.field(paramSym)) - report.warning("Incorrect overriding: " + paramSym.show + " in " + klass.show + " has a different value from " + overridingSym.show + " in " + overridingSym.owner.show, overridingSym.defTree) - - // ---------------------- Semantic definition -------------------------------- - - /** Evaluate a list of expressions */ - def eval(exprs: List[Tree], thisV: ThisRef, klass: ClassSymbol): Contextual[List[Value]] = - exprs.map { expr => eval(expr, thisV, klass) } - - /** Evaluate arguments of methods */ - def evalArgs(args: List[Arg], thisV: ThisRef, klass: ClassSymbol): Contextual[List[Value]] = - for arg <- args yield eval(arg.tree, thisV, klass) - - /** Evaluate an expression with the given value for `this` in a given class `klass` - * - * Note that `klass` might be a super class of the object referred by `thisV`. - * The parameter `klass` is needed for `this` resolution. Consider the following code: - * - * class A { - * A.this - * class B extends A { A.this } - * } - * - * As can be seen above, the meaning of the expression `A.this` depends on where - * it is located. - * - */ - def eval(expr: Tree, thisV: ThisRef, klass: ClassSymbol): Contextual[Value] = - expr match - case Ident(nme.WILDCARD) => - Skolem(expr) - - case id @ Ident(name) if !id.symbol.is(Flags.Method) => - assert(name.isTermName, "type trees should not reach here") - eval(expr.tpe, thisV, klass, expr) - - case Select(qualifier, name) => - val qual = eval(qualifier, thisV, klass) - - name match - case OuterSelectName(_, _) => - Skolem(expr) - case _ => - qual.select(expr.symbol, receiver = qualifier.tpe, source = expr) - - case _: This => - eval(expr.tpe, thisV, klass, expr) - - case Typed(expr, tpt) => - eval(expr, thisV, klass) - - case NamedArg(name, arg) => - eval(arg, thisV, klass) - - case Literal(_) => - Skolem(expr) - - case _ => - Skolem(expr) - - /** Handle semantics of leaf nodes */ - def eval(tp: Type, thisV: ThisRef, klass: ClassSymbol, source: Tree): Contextual[Value] = log("evaluating " + tp.show, printer) { - tp match - case _: ConstantType => - Skolem(source) - - case tmref: TermRef if tmref.prefix == NoPrefix => - val sym = tmref.symbol - - if sym.is(Flags.Param) && sym.owner.isConstructor then - val enclosingClass = sym.owner.enclosingClass.asClass - if enclosingClass == klass then - thisV.field(sym) - else - Skolem(source) - else - Skolem(source) - - case tmref: TermRef => - val cls = tmref.widenSingleton.classSymbol - if cls.exists && cls.isStaticOwner then - if cls == klass || cls == thisV.klass then - thisV - else - Skolem(source) - else - eval(tmref.prefix, thisV, klass, source).select(tmref.symbol, receiver = tmref.prefix, source = source) - - case tp @ ThisType(tref) => - val cls = tref.classSymbol.asClass - if cls == klass then - thisV - else - Skolem(source) - - case _ => - report.error("[Internal error] unexpected type " + tp, source) - Skolem(source) - } - - /** Initialize part of an abstract object in `klass` of the inheritance chain */ - def init(tpl: Template, thisV: ThisRef, klass: ClassSymbol): Contextual[Unit] = log("init " + klass.show, printer) { - val paramsMap = tpl.constr.termParamss.flatten.map { vdef => - vdef.name -> thisV.field(vdef.symbol) - }.toMap - - // init param fields from class parameters - klass.paramGetters.foreach { acc => - val value = paramsMap(acc.name.toTermName) - thisV.initField(acc, value) - printer.println(acc.show + " initialized with " + value) - } - - def superCall(tref: TypeRef, ctor: Symbol, args: List[Value]): Unit = - val cls = tref.classSymbol.asClass - - // follow constructor - if ctor.hasSource then - printer.println("init super class " + cls.show) - thisV.callConstructor(ctor, args) - - // parents - def initParent(parent: Tree) = - parent match - case tree @ Block(stats, NewExpr(tref, New(tpt), ctor, argss)) => // can happen - val ctx2 = ctx.withProperty(IsInSuperCall, Some(true)) - val args = evalArgs(argss.flatten, thisV, klass)(using ctx2) - superCall(tref, ctor, args) - - case tree @ NewExpr(tref, New(tpt), ctor, argss) => // extends A(args) - val ctx2 = ctx.withProperty(IsInSuperCall, Some(true)) - val args = evalArgs(argss.flatten, thisV, klass)(using ctx2) - superCall(tref, ctor, args) - - case _ => // extends A or extends A[T] - val tref = Semantic.typeRefOf(parent.tpe) - superCall(tref, tref.classSymbol.primaryConstructor, Nil) - - // see spec 5.1 about "Template Evaluation". - // https://www.scala-lang.org/files/archive/spec/2.13/05-classes-and-objects.html - if !klass.is(Flags.Trait) then - // 1. first init parent class recursively - // 2. initialize traits according to linearization order - val superParent = tpl.parents.head - val superCls = superParent.tpe.classSymbol.asClass - initParent(superParent) - - val parents = tpl.parents.tail - val mixins = klass.baseClasses.tail.takeWhile(_ != superCls) - - // The interesting case is the outers for traits. The compiler - // synthesizes proxy accessors for the outers in the class that extends - // the trait. As those outers must be stable values, they are initialized - // immediately following class parameters and before super constructor - // calls and user code in the class body. - mixins.reverse.foreach { mixin => - parents.find(_.tpe.classSymbol == mixin) match - case Some(parent) => - initParent(parent) - - case None => - // According to the language spec, if the mixin trait requires - // arguments, then the class must provide arguments to it explicitly - // in the parent list. That means we will encounter it in the Some - // branch. - // - // When a trait A extends a parameterized trait B, it cannot provide - // term arguments to B. That can only be done in a concrete class. - val tref = Semantic.typeRefOf(klass.typeRef.baseType(mixin).typeConstructor) - val ctor = tref.classSymbol.primaryConstructor - if ctor.exists then - superCall(tref, ctor, args = Nil) - } - end if - - // skip class body - } diff --git a/tests/init/neg/class-param.check b/tests/init/neg/class-param.check deleted file mode 100644 index d5add9eda6b7..000000000000 --- a/tests/init/neg/class-param.check +++ /dev/null @@ -1,4 +0,0 @@ --- Error: tests/init/neg/class-param.scala:7:15 ------------------------------------------------------------------------ -7 | override val y: Int = 20 // error: overriding parameter with non-parameter - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | Overriding parameter value y in class B as non-parameter in class C diff --git a/tests/init/neg/class-param.scala b/tests/init/neg/class-param.scala deleted file mode 100644 index 2b09ccf41275..000000000000 --- a/tests/init/neg/class-param.scala +++ /dev/null @@ -1,7 +0,0 @@ -class A(x: Int) - -class B(val y: Int) extends A(y): - println(y) // no warning, parameter access - -class C extends B(10): - override val y: Int = 20 // error: overriding parameter with non-parameter diff --git a/tests/init/neg/i15764.scala b/tests/init/neg/i15764.scala deleted file mode 100644 index 0c7a0b27ad71..000000000000 --- a/tests/init/neg/i15764.scala +++ /dev/null @@ -1,7 +0,0 @@ -class B(val y: Int): - println(y) // A warning is due here - foo() - def foo() = println(y) - -class C(override val y: Int) extends B(10) // error - diff --git a/tests/init/neg/i15764b.scala b/tests/init/neg/i15764b.scala deleted file mode 100644 index 488969e3ebba..000000000000 --- a/tests/init/neg/i15764b.scala +++ /dev/null @@ -1,7 +0,0 @@ -class B(val y: Int): - // println(y) - // foo() - def foo() = println(y) - -class C(x: Int) extends B(x): - override val y: Int = x // error: override param with non-param diff --git a/tests/init/neg/i15764c.scala b/tests/init/neg/i15764c.scala deleted file mode 100644 index 33735fbaf7a5..000000000000 --- a/tests/init/neg/i15764c.scala +++ /dev/null @@ -1,5 +0,0 @@ -class A(val y: Int) - -class B(override val y: Int) extends A(y) - -class C(override val y: Int) extends B(7) // error diff --git a/tests/init/neg/i15764d.scala b/tests/init/neg/i15764d.scala deleted file mode 100644 index 0591a1edc005..000000000000 --- a/tests/init/neg/i15764d.scala +++ /dev/null @@ -1,9 +0,0 @@ -class A(val y: Int) - -abstract class B(override val y: Int) extends A(10) // error - -class C extends B(7) - -class X(val y: Int) - -abstract class Y(override val y: Int) extends A(10) // error diff --git a/tests/init/neg/i15764e.scala b/tests/init/neg/i15764e.scala deleted file mode 100644 index 08d8b3b5e48e..000000000000 --- a/tests/init/neg/i15764e.scala +++ /dev/null @@ -1,18 +0,0 @@ -trait A(val x: Int) -trait B(override val x: Int) extends A // error -class C extends B(1) with A(2) - - -trait X(val x: Int) -trait Y(override val x: Int) extends X // error -class Z extends X(1) with Y(2) - -object Pos1: - trait X(val x: Int) - trait Y(override val x: Int) extends X // ok - class Z(n: Int) extends X(n) with Y(n) - -object Pos2: - trait X(val x: Int) - trait Y(override val x: Int) extends X // ok - class Z(n: Int) extends Y(n) with X(n) diff --git a/tests/init/pos/i15764.scala b/tests/init/pos/i15764.scala deleted file mode 100644 index a7cf5dcbcef4..000000000000 --- a/tests/init/pos/i15764.scala +++ /dev/null @@ -1,6 +0,0 @@ -class B(val y: Int): - println(y) // should not issue a warning here - foo() - def foo() = println(y) - -class C(override val y: Int) extends B(y) diff --git a/tests/init/pos/i15764b.scala b/tests/init/pos/i15764b.scala deleted file mode 100644 index ceca2585d7c8..000000000000 --- a/tests/init/pos/i15764b.scala +++ /dev/null @@ -1,8 +0,0 @@ -class A(val y: Int): - println(y) // should not issue a warning here - foo() - def foo() = println(y) - -class B(z: Int) extends A(z) - -class C(override val y: Int) extends B(y) diff --git a/tests/init/pos/i15764c.scala b/tests/init/pos/i15764c.scala deleted file mode 100644 index b2ed70c9d7b6..000000000000 --- a/tests/init/pos/i15764c.scala +++ /dev/null @@ -1,9 +0,0 @@ -class A(val y: Int): - println(y) // should not issue a warning here - foo() - def foo() = println(y) - -class B(m: Int, n: Int) extends A(m): - def this(z: Int) = this(z, z) - -class C(override val y: Int) extends B(y) diff --git a/tests/init/pos/i15764d.scala b/tests/init/pos/i15764d.scala deleted file mode 100644 index 3782c850c88f..000000000000 --- a/tests/init/pos/i15764d.scala +++ /dev/null @@ -1,13 +0,0 @@ -class A(val y: Int): - println(y) // should not issue a warning here - foo() - def foo() = println(y) - -class B(m: Int, n: Int) extends A(m): - def this(z: Int) = this(z, z) - -class C(override val y: Int) extends B(y) - -class D extends C(10) - -class E extends C(new A(20).y) diff --git a/tests/init/pos/i15764e.scala b/tests/init/pos/i15764e.scala deleted file mode 100644 index 0d47ec20deee..000000000000 --- a/tests/init/pos/i15764e.scala +++ /dev/null @@ -1,3 +0,0 @@ -trait X(val x: Int, y: Int, z: Int) -trait Y(override val x: Int, y: Int, z: Int) extends X -class Z(override val x: Int, y: Int, z: Int) extends Y(x, y, z) with X(x, y, z)