diff --git a/src/dotty/annotation/internal/Repeated.scala b/src/dotty/annotation/internal/Repeated.scala new file mode 100644 index 000000000000..94e9df858d1f --- /dev/null +++ b/src/dotty/annotation/internal/Repeated.scala @@ -0,0 +1,5 @@ +package dotty.annotation.internal + +import scala.annotation.Annotation + +final class Repeated() extends Annotation \ No newline at end of file diff --git a/src/dotty/tools/dotc/Compiler.scala b/src/dotty/tools/dotc/Compiler.scala index 36af6a438035..a4a8fbbc84b1 100644 --- a/src/dotty/tools/dotc/Compiler.scala +++ b/src/dotty/tools/dotc/Compiler.scala @@ -21,7 +21,6 @@ class Compiler { List( List(new FrontEnd), List(new LazyValsCreateCompanionObjects, - /* new Constructors, */ new TailRec), //force separataion between lazyVals and LVCreateCO List(new PatternMatcher, new LazyValTranformContext().transformer, @@ -30,7 +29,8 @@ class Compiler { new TypeTestsCasts, new InterceptedMethods), List(new Erasure), - List(new UncurryTreeTransform, new CollectEntryPoints) + List(new UncurryTreeTransform + /* , new Constructors */) ) var runId = 1 diff --git a/src/dotty/tools/dotc/Main.scala b/src/dotty/tools/dotc/Main.scala index 72f29fe6e9db..0b136d72f7b9 100644 --- a/src/dotty/tools/dotc/Main.scala +++ b/src/dotty/tools/dotc/Main.scala @@ -9,8 +9,6 @@ import core.Contexts.Context import reporting.Reporter /* To do: -s * - Revise the way classes are inherited - when not followed by [...] or (...), - * assume the unparameterized type and forward type parameters as we do now for the synthetic head class. */ object Main extends Driver { def resident(compiler: Compiler): Reporter = unsupported("resident") /*loop { line => diff --git a/src/dotty/tools/dotc/Run.scala b/src/dotty/tools/dotc/Run.scala index 247fa43365e1..a639b20cd770 100644 --- a/src/dotty/tools/dotc/Run.scala +++ b/src/dotty/tools/dotc/Run.scala @@ -42,8 +42,10 @@ class Run(comp: Compiler)(implicit ctx: Context) { phase.runOn(units) def foreachUnit(op: Context => Unit)(implicit ctx: Context): Unit = for (unit <- units) op(ctx.fresh.setPhase(phase.next).setCompilationUnit(unit)) - if (ctx.settings.Xprint.value.containsPhase(phase)) foreachUnit(printTree) - if (ctx.settings.Ycheck.value.containsPhase(phase)) foreachUnit(TreeChecker.check) + if (ctx.settings.Xprint.value.containsPhase(phase)) + foreachUnit(printTree) + if (ctx.settings.Ycheck.value.containsPhase(phase) && !ctx.reporter.hasErrors) + foreachUnit(TreeChecker.check) } } } diff --git a/src/dotty/tools/dotc/ast/Desugar.scala b/src/dotty/tools/dotc/ast/Desugar.scala index 8d891b9d96a8..513dee2ffe2a 100644 --- a/src/dotty/tools/dotc/ast/Desugar.scala +++ b/src/dotty/tools/dotc/ast/Desugar.scala @@ -751,7 +751,9 @@ object desugar { makeBinop(l, op, r) case PostfixOp(t, op) => if ((ctx.mode is Mode.Type) && op == nme.raw.STAR) - AppliedTypeTree(ref(defn.RepeatedParamType), t) + Annotated( + New(ref(defn.RepeatedAnnot.typeRef), Nil :: Nil), + AppliedTypeTree(ref(defn.SeqClass.typeRef), t)) else { assert(ctx.mode.isExpr, ctx.mode) Select(t, op) diff --git a/src/dotty/tools/dotc/ast/Trees.scala b/src/dotty/tools/dotc/ast/Trees.scala index 2ae494d558dc..e11bdeefc810 100644 --- a/src/dotty/tools/dotc/ast/Trees.scala +++ b/src/dotty/tools/dotc/ast/Trees.scala @@ -180,6 +180,8 @@ object Trees { def tokenPos: Seq[(Token, Position)] = ??? } + private var nextId = 0 + /** Trees take a parameter indicating what the type of their `tpe` field * is. Two choices: `Type` or `Untyped`. * Untyped trees have type `Tree[Untyped]`. @@ -204,6 +206,15 @@ object Trees { if (Stats.enabled) ntrees += 1 + /** A unique identifier for this tree. Used for debugging, and potentially + * tracking presentation compiler interactions + */ + val uniqueId = { + nextId += 1 + //assert(nextId != 214, this) + nextId + } + /** The type constructor at the root of the tree */ type ThisTree[T >: Untyped] <: Tree[T] diff --git a/src/dotty/tools/dotc/ast/tpd.scala b/src/dotty/tools/dotc/ast/tpd.scala index e9775f1dc9c0..3b240ad2ca57 100644 --- a/src/dotty/tools/dotc/ast/tpd.scala +++ b/src/dotty/tools/dotc/ast/tpd.scala @@ -210,8 +210,24 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { def TypeDef(sym: TypeSymbol)(implicit ctx: Context): TypeDef = ta.assignType(untpd.TypeDef(Modifiers(sym), sym.name, TypeTree(sym.info)), sym) - def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree])(implicit ctx: Context): TypeDef = { - val parents = cls.info.parents map (TypeTree(_)) + def ClassDef(cls: ClassSymbol, constr: DefDef, body: List[Tree], superArgs: List[Tree] = Nil)(implicit ctx: Context): TypeDef = { + val firstParent :: otherParents = cls.info.parents + val superRef = + if (cls is Trait) TypeTree(firstParent) + else { + def isApplicable(ctpe: Type): Boolean = ctpe match { + case ctpe: PolyType => + isApplicable(ctpe.instantiate(firstParent.argTypes)) + case ctpe: MethodType => + (superArgs corresponds ctpe.paramTypes)(_.tpe <:< _) + case _ => + false + } + val constr = firstParent.decl(nme.CONSTRUCTOR).suchThat(constr => isApplicable(constr.info)) + New(firstParent, constr.symbol.asTerm, superArgs) + } + val parents = superRef :: otherParents.map(TypeTree(_)) + val selfType = if (cls.classInfo.selfInfo ne NoType) ValDef(ctx.newSelfSym(cls)) else EmptyValDef @@ -260,10 +276,13 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo { // ------ Creating typed equivalents of trees that exist only in untyped form ------- - /** new C(args) */ - def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = { + /** new C(args), calling the primary constructor of C */ + def New(tp: Type, args: List[Tree])(implicit ctx: Context): Apply = + New(tp, tp.typeSymbol.primaryConstructor.asTerm, args) + + /** new C(args), calling given constructor `constr` of C */ + def New(tp: Type, constr: TermSymbol, args: List[Tree])(implicit ctx: Context): Apply = { val targs = tp.argTypes - val constr = tp.typeSymbol.primaryConstructor.asTerm Apply( Select( New(tp withoutArgs targs), diff --git a/src/dotty/tools/dotc/config/Config.scala b/src/dotty/tools/dotc/config/Config.scala index e77b10bfbaec..c247699da351 100644 --- a/src/dotty/tools/dotc/config/Config.scala +++ b/src/dotty/tools/dotc/config/Config.scala @@ -37,4 +37,10 @@ object Config { /** The recursion depth for showing a summarized string */ final val summarizeDepth = 2 + + /** Track dependencies for constraint propagation satisfiability checking + * If turned off, constraint checking is simpler but potentially slower + * for large constraints. + */ + final val trackConstrDeps = true } \ No newline at end of file diff --git a/src/dotty/tools/dotc/config/PathResolver.scala b/src/dotty/tools/dotc/config/PathResolver.scala index 34678ae2bf54..f9f698e7238c 100644 --- a/src/dotty/tools/dotc/config/PathResolver.scala +++ b/src/dotty/tools/dotc/config/PathResolver.scala @@ -148,7 +148,7 @@ object PathResolver { println(Defaults) } else { - implicit val ctx = (new ContextBase).initialCtx + implicit val ctx: Context = (new ContextBase).initialCtx // Dotty deviation: implicits need explicit type val ArgsSummary(sstate, rest, errors) = ctx.settings.processArguments(args.toList, true) errors.foreach(println) diff --git a/src/dotty/tools/dotc/core/Constraint.scala b/src/dotty/tools/dotc/core/Constraint.scala index 64fb8764ebb6..339dbb64a343 100644 --- a/src/dotty/tools/dotc/core/Constraint.scala +++ b/src/dotty/tools/dotc/core/Constraint.scala @@ -10,6 +10,55 @@ import printing.Texts._ import config.Config import config.Printers._ +object Constraint { + + /** The type of `Constraint#myMap` */ + type ParamInfo = SimpleMap[PolyType, Array[Type]] + + /** The type of `Constraint#dependents */ + type DependentMap = SimpleMap[PolyType, Array[Set[PolyParam]]] + + /** The type of functions that include or exclude a `PolyParam` in or from a set*/ + private type DepDelta = (Set[PolyParam], PolyParam) => Set[PolyParam] + + private val addDep: DepDelta = (_ + _) + private val removeDep: DepDelta = (_ - _) + + private val NoTypeBounds = new TypeBounds(WildcardType, WildcardType){} + + /** An accumulator that changes dependencies on `param`. + * @param param The parameter to which changed dependencies refer. + * @param ofVariance Include `PolyParams` occurring at this variance in the dependencies. + * @param delta The dependency change to perform (add or remove). + */ + private class ChangeDependencies(param: PolyParam, ofVariance: Int, delta: DepDelta)(implicit ctx: Context) + extends TypeAccumulator[DependentMap] { + def apply(deps: DependentMap, tp: Type): DependentMap = tp match { + case tp @ PolyParam(pt, n) if + this.variance == 0 || this.variance == ofVariance => + val oldDeps = deps(pt) + val original = safeSelect(oldDeps, n) + val changed = delta(original, param) + if (original eq changed) deps + else { + val newDeps = + if (oldDeps == null) new Array[Set[PolyParam]](pt.paramBounds.length) + else oldDeps.clone + newDeps(n) = changed + deps.updated(pt, newDeps) + } + case _ => foldOver(deps, tp) + } + } + + /** `deps(n)`, except that `Set()` is returned if `deps` or `deps(n)` are null */ + private def safeSelect(deps: Array[Set[PolyParam]], n: Int) : Set[PolyParam] = + if (deps == null || deps(n) == null) Set() + else deps(n) +} + +import Constraint._ + /** Constraint over undetermined type parameters * @param myMap a map from PolyType to arrays. * Each array contains twice the number of entries as there a type parameters @@ -18,8 +67,20 @@ import config.Printers._ * track the corresponding parameters, or is left empty (filled with nulls). * An instantiated type parameter is represented by having its instance type in * the corresponding array entry. + * @param dependents a map from PolyTypes to arrays of Sets of PolyParams. + * The i'th set in an array corresponding to polytype `pt` contains + * those dependent `PolyParam`s `dp` that have `PolyParam(pt, i)` in their bounds in + * significant position. A position is significant if solving the + * constraint for `(pt, i)` with a type higher than its lower bound + * would lead to a constraint for `dp` that was not looser than + * the existing constraint. Specifically, it means that all poly params + * appearing covariantly in the lower bound and contravariantly in the + * upper bound, as well as all poly params appearing nonvariantly are + * significant. + * The `dependents` map is maintained and queried only of `Config.trackConstrDeps` is set. */ -class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable { +class Constraint(private val myMap: ParamInfo, + private val dependents: DependentMap) extends Showable { /** Does the constraint's domain contain the type parameters of `pt`? */ def contains(pt: PolyType): Boolean = myMap(pt) != null @@ -66,16 +127,88 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable { def typeVarOfParam(param: PolyParam): Type = { val entries = myMap(param.binder) if (entries == null) NoType - else typeVar(entries, param.paramNum) + else { + val tvar = typeVar(entries, param.paramNum) + if (tvar != null) tvar else NoType + } + } + + /** Change dependencies in map `deps` to reflect new parameter bounds. + * @param deps The map to change + * @param pt the polytype that contains the parameters which might have new bounds + * @param entries the entries for the parameters which might have new bounds + * @param delta the change operation, one of `addDep` or `removeDep`. + * @param cmpEntries the comparison entries or `null` if no such entries exist. + * As an optimization, only bounds that differ between `entries` + * and `cmpEntries` will record their dependencies. + */ + def changeDependencies(deps: DependentMap, pt: PolyType, entries: Array[Type], delta: DepDelta, cmpEntries: Array[Type])(implicit ctx: Context): DependentMap = { + val limit = paramCount(entries) + def loop(deps: DependentMap, n: Int): DependentMap = { + if (n >= limit) deps + else { + val newDeps = entries(n) match { + case bounds @ TypeBounds(lo, hi) => + val cmpBounds = + if (cmpEntries == null) NoTypeBounds + else cmpEntries(n) match { + case bounds: TypeBounds => bounds + case _ => NoTypeBounds + } + if (cmpBounds eq bounds) deps + else { + val param = PolyParam(pt, n) + val deps1 = + if (cmpBounds.lo eq lo) deps + else new ChangeDependencies(param, 1, delta).apply(deps, lo) + val deps2 = + if (cmpBounds.hi eq hi) deps1 + else new ChangeDependencies(param, -1, delta).apply(deps1, hi) + deps2 + } + case _ => + deps + } + loop(newDeps, n + 1) + } + } + if (Config.trackConstrDeps) loop(deps, 0) else deps } + /** Change dependencies to reflect all changes between the bounds in `oldMap` and `newMap`. + */ + def diffDependencies(deps: DependentMap, oldMap: ParamInfo, newMap: ParamInfo)(implicit ctx: Context): DependentMap = + if (Config.trackConstrDeps) { + var d = deps + oldMap foreachBinding { (poly, entries) => + val newEntries = newMap(poly) + if (newEntries ne entries) d = changeDependencies(d, poly, entries, removeDep, newEntries) + } + newMap foreachBinding { (poly, entries) => + val oldEntries = oldMap(poly) + if (oldEntries ne entries) d = changeDependencies(d, poly, entries, addDep, oldEntries) + } + d + } else deps + + /** The set of parameters that depend directly on `param` + * according to what's stored in `dependents`. + */ + def dependentParams(param: PolyParam): Set[PolyParam] = + safeSelect(dependents(param.binder), param.paramNum) + /** A new constraint which is derived from this constraint by adding or replacing * the entries corresponding to `pt` with `entries`. */ private def updateEntries(pt: PolyType, entries: Array[Type])(implicit ctx: Context) : Constraint = { - val res = new Constraint(myMap.updated(pt, entries)) + val res = new Constraint( + myMap.updated(pt, entries), + changeDependencies(dependents, pt, entries, addDep, myMap(pt))) + + //assert(res.domainPolys.filter(pt => + // pt.resultType.resultType.widen.classSymbol.name.toString == "Ensuring").length < 2) //DEBUG if (Config.checkConstraintsNonCyclic) checkNonCyclic(pt, entries) - ctx.runInfo.recordConstraintSize(res) + ctx.runInfo.recordConstraintSize(res, res.myMap.size) res } @@ -114,7 +247,10 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable { updateEntries(poly, myMap(poly) map op) /** A new constraint with all entries coming from `pt` removed. */ - def remove(pt: PolyType) = new Constraint(myMap remove pt) + def remove(pt: PolyType)(implicit ctx: Context) = + new Constraint( + myMap remove pt, + changeDependencies(dependents, pt, myMap(pt), removeDep, null)) /** Is entry associated with `pt` removable? * @param removedParam The index of a parameter which is still present in the @@ -185,7 +321,10 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable { val pt = param.binder val constr1 = if (isRemovable(pt, param.paramNum)) remove(pt) else updated(param, tp) - val result = new Constraint(constr1.myMap mapValues subst) + val substMap = constr1.myMap mapValues subst + val result = new Constraint( + substMap, + diffDependencies(constr1.dependents, constr1.myMap, substMap)) if (Config.checkConstraintsNonCyclic) result.checkNonCyclic() result } @@ -243,6 +382,16 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable { if isBounds(entries(n)) } yield PolyParam(poly, n) + /** Check whether predicate holds for all parameters in constraint + */ + def forallParams(p: PolyParam => Boolean): Boolean = { + myMap.foreachBinding { (poly, entries) => + for (i <- 0 until paramCount(entries)) + if (isBounds(entries(i)) && !p(PolyParam(poly, i))) return false + } + true + } + /** Perform operation `op` on all typevars, or only on uninstantiated * typevars, depending on whether `uninstOnly` is set or not. */ @@ -299,9 +448,9 @@ class Constraint(val myMap: SimpleMap[PolyType, Array[Type]]) extends Showable { trait ConstraintRunInfo { self: RunInfo => private var maxSize = 0 private var maxConstraint: Constraint = _ - def recordConstraintSize(c: Constraint) = - if (c.myMap.size > maxSize) { - maxSize = c.myMap.size + def recordConstraintSize(c: Constraint, size: Int) = + if (size > maxSize) { + maxSize = size maxConstraint = c } def printMaxConstraint()(implicit ctx: Context) = diff --git a/src/dotty/tools/dotc/core/Definitions.scala b/src/dotty/tools/dotc/core/Definitions.scala index 9497438f2f33..6f34efc8bcc8 100644 --- a/src/dotty/tools/dotc/core/Definitions.scala +++ b/src/dotty/tools/dotc/core/Definitions.scala @@ -30,6 +30,9 @@ class Definitions { private def newCompleteClassSymbol(owner: Symbol, name: TypeName, flags: FlagSet, parents: List[TypeRef], decls: Scope = newScope) = ctx.newCompleteClassSymbol(owner, name, flags | Permanent, parents, decls).entered + private def newTopClassSymbol(name: TypeName, flags: FlagSet, parents: List[TypeRef]) = + completeClass(newCompleteClassSymbol(ScalaPackageClass, name, flags, parents)) + private def newTypeParam(cls: ClassSymbol, name: TypeName, flags: FlagSet, scope: MutableScope) = scope.enter(newSymbol(cls, name, flags | TypeParamCreationFlags, TypeBounds.empty)) @@ -74,7 +77,7 @@ class Definitions { newPolyMethod(cls, name, 1, resultTypeFn, flags) private def newT1EmptyParamsMethod(cls: ClassSymbol, name: TermName, resultTypeFn: PolyType => Type, flags: FlagSet) = - newPolyMethod(cls, name, 1, pt => MethodType(Nil, Nil, resultTypeFn(pt)), flags) + newPolyMethod(cls, name, 1, pt => MethodType(Nil, resultTypeFn(pt)), flags) private def mkArityArray(name: String, arity: Int, countFrom: Int): Array[ClassSymbol] = { val arr = new Array[ClassSymbol](arity + 1) @@ -82,6 +85,12 @@ class Definitions { arr } + private def completeClass(cls: ClassSymbol): ClassSymbol = { + ensureConstructor(cls, EmptyScope) + if (cls.linkedClass.exists) cls.linkedClass.info = NoType + cls + } + lazy val RootClass: ClassSymbol = ctx.newPackageSymbol( NoSymbol, nme.ROOT, (root, rootcls) => ctx.rootLoader(root)).moduleClass.asClass lazy val RootPackage: TermSymbol = ctx.newSymbol( @@ -95,58 +104,67 @@ class Definitions { lazy val JavaPackageVal = ctx.requiredPackage("java") lazy val JavaLangPackageVal = ctx.requiredPackage("java.lang") - lazy val ObjectClass = ctx.requiredClass("java.lang.Object") - lazy val AnyRefAlias: TypeSymbol = newAliasType(tpnme.AnyRef, ObjectType) - - lazy val Object_## = newMethod(ObjectClass, nme.HASHHASH, ExprType(IntType), Final) - lazy val Object_== = newMethod(ObjectClass, nme.EQ, methOfAny(BooleanType), Final) - lazy val Object_!= = newMethod(ObjectClass, nme.NE, methOfAny(BooleanType), Final) - lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final) - lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final) - lazy val Object_isInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.isInstanceOf_Ob, _ => BooleanType, Final | Synthetic) - lazy val Object_asInstanceOf = newT1ParameterlessMethod(ObjectClass, nme.asInstanceOf_Ob, PolyParam(_, 0), Final | Synthetic) - lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1, - pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final) - - def Object_getClass = objMethod(nme.getClass_) - def Object_clone = objMethod(nme.clone_) - def Object_finalize = objMethod(nme.finalize_) - def Object_notify = objMethod(nme.notify_) - def Object_notifyAll = objMethod(nme.notifyAll_) - def Object_equals = objMethod(nme.equals_) - def Object_hashCode = objMethod(nme.hashCode_) - def Object_toString = objMethod(nme.toString_) - private def objMethod(name: PreName) = ObjectClass.requiredMethod(name) - - lazy val AnyClass: ClassSymbol = { - val cls = newCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil) - ensureConstructor(cls, EmptyScope) - cls - } - - lazy val AnyValClass: ClassSymbol = ctx.requiredClass("scala.AnyVal") + /** Note: We cannot have same named methods defined in Object and Any (and AnyVal, for that matter) + * because after erasure the Any and AnyVal references get remapped to the Object methods + * which would result in a double binding assertion failure. + * Instead we do the following: + * + * - Have some methods exist only in Any, and remap them with the Erasure denotation + * transformer to be owned by Object. + * - Have other methods exist only in Object. + * To achieve this, we synthesize all Any and Object methods; Object methods no longer get + * loaded from a classfile. + * + * There's a remaining question about `getClass`. In Scala2.x `getClass` was handled by compiler magic. + * This is deemed too cumersome for Dotty and therefore right now `getClass` gets no special treatment; + * it's just a method on `Any` which returns the raw type `java.lang.Class`. An alternative + * way to get better `getClass` typing would be to treat `getClass` as a method of a generic + * decorator which gets remapped in a later phase to Object#getClass. Then we could give it + * the right type without changing the typechecker: + * + * implicit class AnyGetClass[T](val x: T) extends AnyVal { + * def getClass: java.lang.Class[T] = ??? + * } + */ + lazy val AnyClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.Any, Abstract, Nil)) + lazy val AnyValClass: ClassSymbol = completeClass(newCompleteClassSymbol(ScalaPackageClass, tpnme.AnyVal, Abstract, List(AnyClass.typeRef))) - lazy val AnyVal_getClass = AnyValClass.requiredMethod(nme.getClass_) lazy val Any_== = newMethod(AnyClass, nme.EQ, methOfAny(BooleanType), Final) lazy val Any_!= = newMethod(AnyClass, nme.NE, methOfAny(BooleanType), Final) lazy val Any_equals = newMethod(AnyClass, nme.equals_, methOfAny(BooleanType)) - lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, ExprType(IntType)) - lazy val Any_toString = newMethod(AnyClass, nme.toString_, ExprType(StringType)) + lazy val Any_hashCode = newMethod(AnyClass, nme.hashCode_, MethodType(Nil, IntType)) + lazy val Any_toString = newMethod(AnyClass, nme.toString_, MethodType(Nil, StringType)) lazy val Any_## = newMethod(AnyClass, nme.HASHHASH, ExprType(IntType), Final) - - // Any_getClass requires special handling. The return type is determined on - // a per-call-site basis as if the function being called were actually: - // - // // Assuming `target.getClass()` - // def getClass[T](target: T): Class[_ <: T] - // - // Since getClass is not actually a polymorphic method, this requires compiler - // participation. At the "Any" level, the return type is Class[_] as it is in - // java.lang.Object. Java also special cases the return type. - lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, ExprType(Object_getClass.info.resultType), Deferred) + lazy val Any_getClass = newMethod(AnyClass, nme.getClass_, MethodType(Nil, ClassClass.typeRef), Final) lazy val Any_isInstanceOf = newT1ParameterlessMethod(AnyClass, nme.isInstanceOf_, _ => BooleanType, Final) lazy val Any_asInstanceOf = newT1ParameterlessMethod(AnyClass, nme.asInstanceOf_, PolyParam(_, 0), Final) + def AnyMethods = List(Any_==, Any_!=, Any_equals, Any_hashCode, + Any_toString, Any_##, Any_getClass, Any_isInstanceOf, Any_asInstanceOf) + + lazy val ObjectClass: ClassSymbol = { + val cls = ctx.requiredClass("java.lang.Object") + assert(!cls.isCompleted, "race for completing java.lang.Object") + cls.info = ClassInfo(cls.owner.thisType, cls, AnyClass.typeRef :: Nil, newScope) + completeClass(cls) + } + lazy val AnyRefAlias: TypeSymbol = newAliasType(tpnme.AnyRef, ObjectType) + + lazy val Object_eq = newMethod(ObjectClass, nme.eq, methOfAnyRef(BooleanType), Final) + lazy val Object_ne = newMethod(ObjectClass, nme.ne, methOfAnyRef(BooleanType), Final) + lazy val Object_synchronized = newPolyMethod(ObjectClass, nme.synchronized_, 1, + pt => MethodType(List(PolyParam(pt, 0)), PolyParam(pt, 0)), Final) + lazy val Object_clone = newMethod(ObjectClass, nme.clone_, MethodType(Nil, ObjectType), Protected) + lazy val Object_finalize = newMethod(ObjectClass, nme.finalize_, MethodType(Nil, UnitType), Protected) + lazy val Object_notify = newMethod(ObjectClass, nme.notify_, MethodType(Nil, UnitType)) + lazy val Object_notifyAll = newMethod(ObjectClass, nme.notifyAll_, MethodType(Nil, UnitType)) + lazy val Object_wait = newMethod(ObjectClass, nme.wait_, MethodType(Nil, UnitType)) + lazy val Object_waitL = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: Nil, UnitType)) + lazy val Object_waitLI = newMethod(ObjectClass, nme.wait_, MethodType(LongType :: IntType :: Nil, UnitType)) + + def ObjectMethods = List(Object_eq, Object_ne, Object_synchronized, Object_clone, + Object_finalize, Object_notify, Object_notifyAll, Object_wait, Object_waitL, Object_waitLI) + lazy val NotNullClass = ctx.requiredClass("scala.NotNull") lazy val NothingClass: ClassSymbol = newCompleteClassSymbol( @@ -160,6 +178,7 @@ class Definitions { lazy val BoxesRunTimeClass = BoxesRunTimeModule.moduleClass lazy val DottyPredefModule = ctx.requiredModule("dotty.DottyPredef") lazy val NilModule = ctx.requiredModule("scala.collection.immutable.Nil") + lazy val PredefConformsClass = ctx.requiredClass("scala.Predef." + tpnme.Conforms) // lazy val FunctionClass: ClassSymbol = ctx.requiredClass("scala.Function") lazy val SingletonClass: ClassSymbol = @@ -265,6 +284,7 @@ class Definitions { // Annotation classes lazy val AliasAnnot = ctx.requiredClass("dotty.annotation.internal.Alias") lazy val ChildAnnot = ctx.requiredClass("dotty.annotation.internal.Child") + lazy val RepeatedAnnot = ctx.requiredClass("dotty.annotation.internal.Repeated") lazy val InvariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.InvariantBetween") lazy val CovariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.CovariantBetween") lazy val ContravariantBetweenClass = ctx.requiredClass("dotty.annotation.internal.ContravariantBetween") @@ -380,8 +400,8 @@ class Definitions { lazy val PhantomClasses = Set[Symbol](AnyClass, AnyValClass, NullClass, NothingClass) - lazy val asInstanceOfMethods = Set[Symbol](Any_asInstanceOf, Object_asInstanceOf) - lazy val isInstanceOfMethods = Set[Symbol](Any_isInstanceOf, Object_isInstanceOf) + lazy val asInstanceOfMethods = Set[Symbol](Any_asInstanceOf) + lazy val isInstanceOfMethods = Set[Symbol](Any_isInstanceOf) lazy val typeTestsOrCasts = asInstanceOfMethods ++ isInstanceOfMethods lazy val RootImports = List[Symbol](JavaLangPackageVal, ScalaPackageVal, ScalaPredefModule, DottyPredefModule) @@ -518,11 +538,11 @@ class Definitions { /** Lists core classes that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */ lazy val syntheticCoreClasses = List( + AnyClass, AnyRefAlias, RepeatedParamClass, JavaRepeatedParamClass, ByNameParamClass2x, - AnyClass, AnyValClass, NullClass, NothingClass, @@ -531,26 +551,7 @@ class Definitions { EmptyPackageVal) /** Lists core methods that don't have underlying bytecode, but are synthesized on-the-fly in every reflection universe */ - lazy val syntheticCoreMethods = List( - Any_==, - Any_!=, - Any_equals, - Any_hashCode, - Any_toString, - Any_getClass, - Any_isInstanceOf, - Any_asInstanceOf, - Any_##, - Object_eq, - Object_ne, - Object_==, - Object_!=, - Object_##, - Object_synchronized, - Object_isInstanceOf, - Object_asInstanceOf, - String_+ - ) + lazy val syntheticCoreMethods = AnyMethods ++ ObjectMethods ++ List(String_+) private[this] var _isInitialized = false def isInitialized = _isInitialized diff --git a/src/dotty/tools/dotc/core/Denotations.scala b/src/dotty/tools/dotc/core/Denotations.scala index e5f5e6f87529..9eab2bd040f7 100644 --- a/src/dotty/tools/dotc/core/Denotations.scala +++ b/src/dotty/tools/dotc/core/Denotations.scala @@ -600,7 +600,7 @@ object Denotations { case denot: SymDenotation => s"in ${denot.owner}" case _ => "" } - def msg = s"stale symbol; $this#${symbol.id} $ownerMsg, defined in run ${myValidFor.runId}, is referred to in run ${ctx.runId}" + def msg = s"stale symbol; $this#${symbol.id} $ownerMsg, defined in ${myValidFor}, is referred to in run ${ctx.period}" throw new StaleSymbol(msg) } diff --git a/src/dotty/tools/dotc/core/Phases.scala b/src/dotty/tools/dotc/core/Phases.scala index f76b83db69cd..251cd3876113 100644 --- a/src/dotty/tools/dotc/core/Phases.scala +++ b/src/dotty/tools/dotc/core/Phases.scala @@ -36,6 +36,8 @@ trait Phases { def atPhaseNotLaterThanTyper[T](op: Context => T): T = atPhaseNotLaterThan(base.typerPhase)(op) + + def isAfterTyper: Boolean = base.isAfterTyper(phase) } object Phases { @@ -177,9 +179,11 @@ object Phases { def refchecksPhase = refChecksCache.phase def erasurePhase = erasureCache.phase def flattenPhase = flattenCache.phase + + def isAfterTyper(phase: Phase): Boolean = phase.id > typerPhase.id } - final val typerName = "typer" + final val typerName = "frontend" final val refChecksName = "refchecks" final val erasureName = "erasure" final val flattenName = "flatten" diff --git a/src/dotty/tools/dotc/core/StdNames.scala b/src/dotty/tools/dotc/core/StdNames.scala index cb4272f7a267..593feb9092e5 100644 --- a/src/dotty/tools/dotc/core/StdNames.scala +++ b/src/dotty/tools/dotc/core/StdNames.scala @@ -331,7 +331,6 @@ object StdNames { val asType: N = "asType" val asClass: N = "asClass" val asInstanceOf_ : N = "asInstanceOf" - val asInstanceOf_Ob : N = "$asInstanceOf" val assert_ : N = "assert" val assume_ : N = "assume" val box: N = "box" @@ -388,7 +387,6 @@ object StdNames { val isDefinedAt: N = "isDefinedAt" val isEmpty: N = "isEmpty" val isInstanceOf_ : N = "isInstanceOf" - val isInstanceOf_Ob : N = "$isInstanceOf" val java: N = "java" val keepUnions: N = "keepUnions" val key: N = "key" diff --git a/src/dotty/tools/dotc/core/SymDenotations.scala b/src/dotty/tools/dotc/core/SymDenotations.scala index 9cf06ec47f4e..c7e7dc50d13a 100644 --- a/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/src/dotty/tools/dotc/core/SymDenotations.scala @@ -46,8 +46,9 @@ trait SymDenotations { this: Context => case ClassInfo(_, _, _, _, selfInfo) => selfInfo == denot.symbol case _ => false } - stillValid(owner) && owner.isClass && ( - (owner.decls.lookupAll(denot.name) contains denot.symbol) + stillValid(owner) && ( + !owner.isClass + || (owner.decls.lookupAll(denot.name) contains denot.symbol) || isSelfSym ) } catch { diff --git a/src/dotty/tools/dotc/core/TypeApplications.scala b/src/dotty/tools/dotc/core/TypeApplications.scala index 4b251f1839e2..c4845a249de4 100644 --- a/src/dotty/tools/dotc/core/TypeApplications.scala +++ b/src/dotty/tools/dotc/core/TypeApplications.scala @@ -111,7 +111,7 @@ class TypeApplications(val self: Type) extends AnyVal { /** Encode the type resulting from applying this type to given arguments */ final def appliedTo(args: List[Type])(implicit ctx: Context): Type = /*>|>*/ track("appliedTo") /*<|<*/ { - def recur(tp: Type, tparams: List[TypeSymbol], args: List[Type]): Type = args match { + def matchParams(tp: Type, tparams: List[TypeSymbol], args: List[Type]): Type = args match { case arg :: args1 => if (tparams.isEmpty) { println(s"applied type mismatch: $self $args, typeParams = $typeParams, tsym = ${self.typeSymbol.debugString}") // !!! DEBUG @@ -119,32 +119,46 @@ class TypeApplications(val self: Type) extends AnyVal { } val tparam = tparams.head val tp1 = RefinedType(tp, tparam.name, arg.toBounds(tparam)) - recur(tp1, tparams.tail, args1) + matchParams(tp1, tparams.tail, args1) case nil => tp } - def safeTypeParams(tsym: Symbol) = - if (tsym.isClass || !self.typeSymbol.isCompleting) typeParams - else { - ctx.warning("encountered F-bounded higher-kinded type parameters; assuming they are invariant") - defn.hkTrait(args map alwaysZero).typeParams - } - - if (args.isEmpty || !canHaveTypeParams) self - else self match { + /** Instantiate type `tp` with `args`. + * @param original The original type for which we compute the type parameters + * This makes a difference for refinement types, because + * refinements bind type parameters and thereby remove them + * from `typeParams`. + */ + def instantiate(tp: Type, original: Type): Type = tp match { case tp: TypeRef => val tsym = tp.symbol if (tsym.isAliasType) tp.underlying.appliedTo(args) - else recur(tp, safeTypeParams(tsym), args) + else { + val safeTypeParams = + if (tsym.isClass || !tp.typeSymbol.isCompleting) original.typeParams + else { + ctx.warning("encountered F-bounded higher-kinded type parameters; assuming they are invariant") + defn.hkTrait(args map alwaysZero).typeParams + } + matchParams(tp, safeTypeParams, args) + } + case tp: RefinedType => + tp.derivedRefinedType( + instantiate(tp.parent, original), + tp.refinedName, + tp.refinedInfo) case tp: TypeProxy => - tp.underlying.appliedTo(args) + instantiate(tp.underlying, original) case AndType(l, r) => l.appliedTo(args) & r case tp: PolyType => tp.instantiate(args) case ErrorType => - self + tp } + + if (args.isEmpty || !canHaveTypeParams) self + else instantiate(self, self) } final def appliedTo(arg: Type)(implicit ctx: Context): Type = appliedTo(arg :: Nil) diff --git a/src/dotty/tools/dotc/core/TypeComparer.scala b/src/dotty/tools/dotc/core/TypeComparer.scala index cab09826b9b8..6174f0915dff 100644 --- a/src/dotty/tools/dotc/core/TypeComparer.scala +++ b/src/dotty/tools/dotc/core/TypeComparer.scala @@ -32,6 +32,11 @@ class TypeComparer(initctx: Context) extends DotClass { */ protected var ignoreConstraint = false + /** Compare a solution of the constraint instead of the constrained parameters. + * The solution maps every parameter to its lower bound. + */ + protected var solvedConstraint = false + private var needsGc = false /** Is a subtype check in course? In that case we may not @@ -79,14 +84,89 @@ class TypeComparer(initctx: Context) extends DotClass { myAnyType } + /** Map that approximates each param in constraint by its lower bound. + * Currently only used for diagnostics. + */ + val approxParams = new TypeMap { + def apply(tp: Type): Type = tp.stripTypeVar match { + case tp: PolyParam if constraint contains tp => + this(constraint.bounds(tp).lo) + case tp => + mapOver(tp) + } + } + + /** If `param` is contained in constraint, test whether its + * bounds are non-empty. Otherwise return `true`. + */ + private def checkBounds(param: PolyParam): Boolean = constraint.at(param) match { + case TypeBounds(lo, hi) => + if (Stats.monitored) Stats.record("checkBounds") + isSubType(lo, hi) + case _ => true + } + + /** Test validity of constraint for parameter `changed` and of all + * parameters that depend on it. + */ + private def propagate(changed: PolyParam): Boolean = + if (Config.trackConstrDeps) + checkBounds(changed) && + propagate(constraint.dependentParams(changed) - changed, Set(changed)) + else + constraint forallParams checkBounds + + /** Ensure validity of constraints for parameters `params` and of all + * parameters that depend on them and that have not been tested + * now or before. If `trackConstrDeps` is not set, do this for all + * parameters in the constraint. + * @param seen the set of parameters that have been tested before. + */ + private def propagate(params: Set[PolyParam], seen: Set[PolyParam]): Boolean = + params.isEmpty || + (params forall checkBounds) && { + val seen1 = seen ++ params + val nextParams = (Set[PolyParam]() /: params) { (ps, p) => + ps ++ (constraint.dependentParams(p) -- seen1) + } + propagate(nextParams, seen1) + } + + /** Check whether the lower bounds of all parameters in this + * constraint are a solution to the constraint. + * As an optimization, when `trackConstrDeps` is set, we + * only test that the solutions satisfy the constraints `changed` + * and all parameters that depend on it. + */ + def isSatisfiable(changed: PolyParam): Boolean = { + val saved = solvedConstraint + solvedConstraint = true + try + if (Config.trackConstrDeps) propagate(changed) + else + constraint.forallParams { param => + checkBounds(param) || { + val TypeBounds(lo, hi) = constraint.bounds(param) + ctx.log(i"sub fail $lo <:< $hi") + ctx.log(i"approximated = ${approxParams(lo)} <:< ${approxParams(hi)}") + false + } + } + finally solvedConstraint = saved + } + /** Update constraint for `param` to `bounds`, check that * new constraint is still satisfiable. */ private def updateConstraint(param: PolyParam, bounds: TypeBounds): Boolean = { val saved = constraint constraint = constraint.updated(param, bounds) - isSubType(bounds.lo, bounds.hi) || - { constraint = saved; false } // don't leave the constraint in unsatisfiable state + if (propagate(param)) { + if (isSatisfiable(param)) return true + ctx.log(i"SAT $constraint produced by $param $bounds is not satisfiable") + } + constraint = saved // don't leave the constraint in unsatisfiable state + false } private def addConstraint1(param: PolyParam, bound: Type, fromBelow: Boolean): Boolean = { @@ -101,7 +181,7 @@ class TypeComparer(initctx: Context) extends DotClass { finally ignoreConstraint = saved val res = (param == bound) || (oldBounds eq newBounds) || updateConstraint(param, newBounds) - constr.println(s"add constraint $param ${if (fromBelow) ">:" else "<:"} $bound = $res") + constr.println(s"added1 constraint $param ${if (fromBelow) ">:" else "<:"} $bound = $res") if (res) constr.println(constraint.show) res } @@ -127,7 +207,8 @@ class TypeComparer(initctx: Context) extends DotClass { def addConstraint(param: PolyParam, bound0: Type, fromBelow: Boolean): Boolean = { assert(!frozenConstraint) val bound = bound0.dealias.stripTypeVar - constr.println(s"adding ${param.show} ${if (fromBelow) ">:>" else "<:<"} ${bound.show} (${bound.getClass}) to ${constraint.show}") + def description = s"${param.show} ${if (fromBelow) ">:>" else "<:<"} ${bound.show} (${bound.getClass}) to ${constraint.show}" + constr.println(s"adding $description") val res = bound match { case bound: PolyParam if constraint contains bound => val TypeBounds(lo, hi) = constraint.bounds(bound) @@ -150,12 +231,12 @@ class TypeComparer(initctx: Context) extends DotClass { case bound => // !!! remove to keep the originals addConstraint1(param, bound, fromBelow) } - constr.println(s"added ${param.show} ${if (fromBelow) ">:>" else "<:<"} ${bound.show} = ${constraint.show}") + constr.println(s"added $description = ${constraint.show}") res } def isConstrained(param: PolyParam): Boolean = - !frozenConstraint && (constraint contains param) + !frozenConstraint && !solvedConstraint && (constraint contains param) /** Solve constraint set for given type parameter `param`. * If `fromBelow` is true the parameter is approximated by its lower bound, @@ -280,7 +361,7 @@ class TypeComparer(initctx: Context) extends DotClass { tp2 match { case tp2: NamedType => def compareNamed = { - implicit val ctx = this.ctx + implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type tp1 match { case tp1: NamedType => val sym1 = tp1.symbol @@ -305,13 +386,15 @@ class TypeComparer(initctx: Context) extends DotClass { case tp2: ProtoType => isMatchedByProto(tp2, tp1) case tp2: PolyParam => - def comparePolyParam = { - tp2 == tp1 || - isSubTypeWhenFrozen(tp1, bounds(tp2).lo) || { - if (isConstrained(tp2)) addConstraint(tp2, tp1.widen, fromBelow = true) - else (ctx.mode is Mode.TypevarsMissContext) || secondTry(tp1, tp2) - } - } + def comparePolyParam = + tp2 == tp1 || { + if (solvedConstraint && (constraint contains tp2)) isSubType(tp1, bounds(tp2).lo) + else + isSubTypeWhenFrozen(tp1, bounds(tp2).lo) || { + if (isConstrained(tp2)) addConstraint(tp2, tp1.widen, fromBelow = true) + else (ctx.mode is Mode.TypevarsMissContext) || secondTry(tp1, tp2) + } + } comparePolyParam case tp2: BoundType => tp2 == tp1 || secondTry(tp1, tp2) @@ -345,23 +428,25 @@ class TypeComparer(initctx: Context) extends DotClass { case OrType(tp11, tp12) => isSubType(tp11, tp2) && isSubType(tp12, tp2) case tp1: PolyParam => - def comparePolyParam = { - tp1 == tp2 || - isSubTypeWhenFrozen(bounds(tp1).hi, tp2) || { - if (isConstrained(tp1)) - addConstraint(tp1, tp2, fromBelow = false) && { - if ((!frozenConstraint) && - (tp2 isRef defn.NothingClass) && - state.isGlobalCommittable) { - def msg = s"!!! instantiated to Nothing: $tp1, constraint = ${constraint.show}" - if (Config.flagInstantiationToNothing) assert(false, msg) - else ctx.log(msg) - } - true + def comparePolyParam = + tp1 == tp2 || { + if (solvedConstraint && (constraint contains tp1)) isSubType(bounds(tp1).lo, tp2) + else + isSubTypeWhenFrozen(bounds(tp1).hi, tp2) || { + if (isConstrained(tp1)) + addConstraint(tp1, tp2, fromBelow = false) && { + if ((!frozenConstraint) && + (tp2 isRef defn.NothingClass) && + state.isGlobalCommittable) { + def msg = s"!!! instantiated to Nothing: $tp1, constraint = ${constraint.show}" + if (Config.flagInstantiationToNothing) assert(false, msg) + else ctx.log(msg) + } + true + } + else (ctx.mode is Mode.TypevarsMissContext) || thirdTry(tp1, tp2) } - else (ctx.mode is Mode.TypevarsMissContext) || thirdTry(tp1, tp2) } - } comparePolyParam case tp1: BoundType => tp1 == tp2 || thirdTry(tp1, tp2) @@ -590,7 +675,7 @@ class TypeComparer(initctx: Context) extends DotClass { /** Defer constraining type variables when compared against prototypes */ def isMatchedByProto(proto: ProtoType, tp: Type) = tp.stripTypeVar match { - case tp: PolyParam if constraint contains tp => true + case tp: PolyParam if !solvedConstraint && (constraint contains tp) => true case _ => proto.isMatchedBy(tp) } @@ -612,6 +697,12 @@ class TypeComparer(initctx: Context) extends DotClass { i < tparams.length && tparams(i).name == name2 } + /** Is type `tp` a TypeRef referring to a higher-kinded parameter? */ + private def isHKRef(tp: Type) = tp match { + case TypeRef(_, name) => name.isHkParamName + case _ => false + } + /** Can type `tp` be constrained from above by adding a constraint to * a typevar that it refers to? In that case we have to be careful not * to approximate with the lower bound of a type in `thirdTry`. Instead, @@ -619,7 +710,7 @@ class TypeComparer(initctx: Context) extends DotClass { * type variable with (the corresponding type in) `tp2` instead. */ def isCappable(tp: Type): Boolean = tp match { - case tp: PolyParam => constraint contains tp + case tp: PolyParam => !solvedConstraint && (constraint contains tp) case tp: TypeProxy => isCappable(tp.underlying) case tp: AndOrType => isCappable(tp.tp1) || isCappable(tp.tp2) case _ => false @@ -656,7 +747,7 @@ class TypeComparer(initctx: Context) extends DotClass { v == 0 || tparam.variance == v } hk.println(s"isSubTypeHK: args1 = $args1, hk-bounds = $hkBounds $boundsOK $variancesOK") - boundsOK && variancesOK + boundsOK && variancesOK || fourthTry(tp1, tp2) } def trySetType(tr: NamedType, bounds: TypeBounds): Boolean = @@ -895,7 +986,11 @@ class TypeComparer(initctx: Context) extends DotClass { else { val t2 = distributeAnd(tp2, tp1) if (t2.exists) t2 - else AndType(tp1, tp2) + else { + if (isHKRef(tp1)) tp2 + else if (isHKRef(tp2)) tp1 + else AndType(tp1, tp2) + } } } @@ -915,7 +1010,11 @@ class TypeComparer(initctx: Context) extends DotClass { else { val t2 = distributeOr(tp2, tp1) if (t2.exists) t2 - else OrType(tp1, tp2) + else { + if (isHKRef(tp1)) tp1 + else if (isHKRef(tp2)) tp2 + else OrType(tp1, tp2) + } } } diff --git a/src/dotty/tools/dotc/core/TyperState.scala b/src/dotty/tools/dotc/core/TyperState.scala index 6e17767d23e2..59c934e0d39d 100644 --- a/src/dotty/tools/dotc/core/TyperState.scala +++ b/src/dotty/tools/dotc/core/TyperState.scala @@ -14,7 +14,7 @@ import collection.mutable class TyperState(val reporter: Reporter) extends DotClass with Showable { /** The current constraint set */ - def constraint: Constraint = new Constraint(SimpleMap.Empty) + def constraint: Constraint = new Constraint(SimpleMap.Empty, SimpleMap.Empty) def constraint_=(c: Constraint): Unit = {} /** The uninstantiated variables */ @@ -27,6 +27,9 @@ class TyperState(val reporter: Reporter) extends DotClass with Showable { */ def instType(tvar: TypeVar): Type = constraint.at(tvar.origin) match { case _: TypeBounds => NoType + case tp: PolyParam => + var tvar1 = constraint.typeVarOfParam(tp) + if (tvar1.exists) tvar1 else tp case tp => tp } @@ -35,6 +38,9 @@ class TyperState(val reporter: Reporter) extends DotClass with Showable { */ def fresh(isCommittable: Boolean): TyperState = this + /** A fresh type state with the same constraint as this one and the given reporter */ + def withReporter(reporter: Reporter) = new TyperState(reporter) + /** Commit state so that it gets propagated to enclosing context */ def commit()(implicit ctx: Context): Unit = unsupported("commit") @@ -42,7 +48,7 @@ class TyperState(val reporter: Reporter) extends DotClass with Showable { * type variable instantiation cannot be retracted anymore. Then, remove * no-longer needed constraint entries. */ - def gc(): Unit = () + def gc()(implicit ctx: Context): Unit = () /** Is it allowed to commit this state? */ def isCommittable: Boolean = false @@ -64,6 +70,9 @@ extends TyperState(reporter) { override def fresh(isCommittable: Boolean): TyperState = new MutableTyperState(this, new StoreReporter, isCommittable) + override def withReporter(reporter: Reporter) = + new MutableTyperState(this, reporter, isCommittable) + override val isGlobalCommittable = isCommittable && (!previous.isInstanceOf[MutableTyperState] || previous.isGlobalCommittable) @@ -87,7 +96,7 @@ extends TyperState(reporter) { reporter.flush() } - override def gc(): Unit = { + override def gc()(implicit ctx: Context): Unit = { val toCollect = new mutable.ListBuffer[PolyType] constraint foreachTypeVar { tvar => if (!tvar.inst.exists) { diff --git a/src/dotty/tools/dotc/core/Types.scala b/src/dotty/tools/dotc/core/Types.scala index 5ce13ad55a98..088a2e3af987 100644 --- a/src/dotty/tools/dotc/core/Types.scala +++ b/src/dotty/tools/dotc/core/Types.scala @@ -597,7 +597,7 @@ object Types { final def objToAny(implicit ctx: Context) = if ((this isRef defn.ObjectClass) && !ctx.phase.erasedTypes) defn.AnyType else this - /** If this is repeated parameter type, its underlying type, + /** If this is repeated parameter type, its underlying Seq type, * else the type itself. */ def underlyingIfRepeated(implicit ctx: Context): Type = this match { @@ -1314,11 +1314,12 @@ object Types { unique(new NonMemberTermRef(prefix, name, sym)) def withSymAndName(prefix: Type, sym: TermSymbol, name: TermName)(implicit ctx: Context): TermRef = - if (prefix eq NoPrefix) withNonMemberSym(prefix, name, sym) - else { - if (sym.defRunId != NoRunId && sym.isCompleted) withSig(prefix, name, sym.signature) - else apply(prefix, name) - } withSym (sym, Signature.NotAMethod) + if (prefix eq NoPrefix) + withNonMemberSym(prefix, name, sym) + else if (sym.defRunId != NoRunId && sym.isCompleted) + withSig(prefix, name, sym.signature) withSym (sym, sym.signature) + else + apply(prefix, name) withSym (sym, Signature.NotAMethod) def withSig(prefix: Type, sym: TermSymbol)(implicit ctx: Context): TermRef = unique(withSig(prefix, sym.name, sym.signature).withSym(sym, sym.signature)) @@ -1663,9 +1664,15 @@ object Types { def apply(paramTypes: List[Type], resultType: Type)(implicit ctx: Context): MethodType = apply(nme.syntheticParamNames(paramTypes.length), paramTypes, resultType) def fromSymbols(params: List[Symbol], resultType: Type)(implicit ctx: Context) = { + def paramInfo(param: Symbol): Type = param.info match { + case AnnotatedType(annot, tp) if annot matches defn.RepeatedAnnot => + tp.translateParameterized(defn.SeqClass, defn.RepeatedParamClass) + case tp => + tp + } def transformResult(mt: MethodType) = resultType.subst(params, (0 until params.length).toList map (MethodParam(mt, _))) - apply(params map (_.name.asTermName), params map (_.info))(transformResult _) + apply(params map (_.name.asTermName), params map paramInfo)(transformResult _) } } @@ -2112,11 +2119,12 @@ object Types { override def toString = if (lo eq hi) s"TypeAlias($lo)" else s"TypeBounds($lo, $hi)" + + override def computeHash = unsupported("computeHash") } class CachedTypeBounds(lo: Type, hi: Type, hc: Int) extends TypeBounds(lo, hi) { myHash = hc - override def computeHash = unsupported("computeHash") } final class CoTypeBounds(lo: Type, hi: Type, hc: Int) extends CachedTypeBounds(lo, hi, hc) { @@ -2269,7 +2277,7 @@ object Types { /** Map this function over given type */ def mapOver(tp: Type): Type = { - implicit val ctx = this.ctx + implicit val ctx: Context = this.ctx // Dotty deviation: implicits need explicit type tp match { case tp: NamedType => if (stopAtStatic && tp.symbol.isStatic) tp diff --git a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala index f5942dac24b8..0ed301732e8a 100644 --- a/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala +++ b/src/dotty/tools/dotc/core/pickling/ClassfileParser.scala @@ -891,8 +891,10 @@ class ClassfileParser( def getType(index: Int)(implicit ctx: Context): Type = sigToType(getExternalName(index)) - def getSuperClass(index: Int)(implicit ctx: Context): Symbol = - if (index == 0) defn.AnyClass else getClassSymbol(index) + def getSuperClass(index: Int)(implicit ctx: Context): Symbol = { + assert(index != 0, "attempt to parse java.lang.Object from classfile") + getClassSymbol(index) + } def getConstant(index: Int)(implicit ctx: Context): Constant = { if (index <= 0 || len <= index) errorBadIndex(index) diff --git a/src/dotty/tools/dotc/core/transform/Erasure.scala b/src/dotty/tools/dotc/core/transform/Erasure.scala index 9fb580ae8b95..f2e3355fb304 100644 --- a/src/dotty/tools/dotc/core/transform/Erasure.scala +++ b/src/dotty/tools/dotc/core/transform/Erasure.scala @@ -61,8 +61,8 @@ object Erasure { */ def transformInfo(sym: Symbol, tp: Type)(implicit ctx: Context): Type = { val erase = erasureFn(sym is JavaDefined, isSemi = true, sym.isConstructor, wildcardOK = false) - if ((sym eq defn.Object_asInstanceOf) || - (sym eq defn.Object_isInstanceOf) || + if ((sym eq defn.Any_asInstanceOf) || + (sym eq defn.Any_isInstanceOf) || (sym.owner eq defn.ArrayClass) && (sym.isType || sym.isConstructor)) sym.info else if (sym.isAbstractType) TypeAlias(WildcardType) else erase(tp) @@ -124,7 +124,7 @@ class Erasure(isJava: Boolean, isSemi: Boolean, isConstructor: Boolean, wildcard else this(parent) case tp: TermRef => val sym = tp.symbol - if (sym.owner is Package) sym.termRef + if (sym.exists && (sym.owner is Package)) sym.termRef else tp.derivedSelect(this(tp.prefix)) case _: ThisType | _: ConstantType => tp diff --git a/src/dotty/tools/dotc/printing/PlainPrinter.scala b/src/dotty/tools/dotc/printing/PlainPrinter.scala index f10aa7225fcf..308470885fa9 100644 --- a/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -143,7 +143,7 @@ class PlainPrinter(_ctx: Context) extends Printer { toTextLocal(tpe) ~ " " ~ toText(annot) case tp: TypeVar => val suffix = if (tp.isInstantiated) "'" else "?" - toTextLocal(tp.stripTypeVar) ~ suffix // debug for now, so that we can see where the TypeVars are. + toTextLocal(tp.instanceOpt orElse tp.origin) ~ suffix // debug for now, so that we can see where the TypeVars are. case _ => tp.fallbackToText(this) } diff --git a/src/dotty/tools/dotc/transform/Erasure.scala b/src/dotty/tools/dotc/transform/Erasure.scala index 791df341ad09..e6d012d68a6a 100644 --- a/src/dotty/tools/dotc/transform/Erasure.scala +++ b/src/dotty/tools/dotc/transform/Erasure.scala @@ -33,7 +33,10 @@ class Erasure extends Phase with DenotTransformer { def transform(ref: SingleDenotation)(implicit ctx: Context): SingleDenotation = ref match { case ref: SymDenotation => assert(ctx.phase == this, s"transforming $ref at ${ctx.phase}") - ref.copySymDenotation(info = transformInfo(ref.symbol, ref.info)) + val owner = ref.owner + ref.copySymDenotation( + owner = if (owner eq defn.AnyClass) defn.ObjectClass else owner, + info = transformInfo(ref.symbol, ref.info)) case ref => ref.derivedSingleDenotation(ref.symbol, erasure(ref.info)) } @@ -136,7 +139,7 @@ object Erasure { cast(runtimeCall(nme.toObjectArray, tree :: Nil), pt) case _ => ctx.log(s"casting from ${tree.showSummary}: ${tree.tpe.show} to ${pt.show}") - TypeApply(Select(tree, defn.Object_asInstanceOf), TypeTree(pt) :: Nil) + TypeApply(Select(tree, defn.Any_asInstanceOf), TypeTree(pt) :: Nil) } /** Adaptation of an expression `e` to an expected type `PT`, applying the following @@ -195,7 +198,7 @@ object Erasure { */ override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { val sym = tree.symbol - assert(sym.exists) + assert(sym.exists, tree.show) def select(qual: Tree, sym: Symbol): Tree = untpd.cpy.Select(tree, qual, sym.name) withType qual.tpe.select(sym) @@ -242,6 +245,8 @@ object Erasure { case mt: MethodType => val args1 = args.zipWithConserve(mt.paramTypes)(typedExpr) untpd.cpy.Apply(tree, fun1, args1) withType mt.resultType + case _ => + throw new MatchError(i"tree $tree has uxpected type of function ${fun1.tpe.widen}, was ${fun.typeOpt.widen}") } } diff --git a/src/dotty/tools/dotc/transform/InterceptedMethods.scala b/src/dotty/tools/dotc/transform/InterceptedMethods.scala index d5a4377d049d..f5fed6fda760 100644 --- a/src/dotty/tools/dotc/transform/InterceptedMethods.scala +++ b/src/dotty/tools/dotc/transform/InterceptedMethods.scala @@ -28,6 +28,10 @@ import dotty.tools.dotc.core.Denotations.SingleDenotation import dotty.tools.dotc.core.SymDenotations.SymDenotation import StdNames._ +// @DarkDimius The getClass scheme changed. We no longer can have +// two different methods in Any and Object. The tests pass but I +// am not sure Intercepted methods treats getClass right now. +// Please check and delete comment when done. /** Replace member references as follows: * * - `x == y` for == in class Any becomes `x equals y` with equals in class Object. @@ -50,12 +54,10 @@ class InterceptedMethods extends TreeTransform { /** perform context-dependant initialization */ override def init(implicit ctx: Context, info: TransformerInfo): Unit = { - getClassMethods = Set(defn.Any_getClass, defn.AnyVal_getClass) - poundPoundMethods = Set(defn.Any_##, defn.Object_##) + poundPoundMethods = Set(defn.Any_##) Any_comparisons = Set(defn.Any_==, defn.Any_!=) - interceptedMethods = getClassMethods ++ poundPoundMethods ++ Any_comparisons - primitiveGetClassMethods = Set[Symbol](defn.Any_getClass, defn.AnyVal_getClass) ++ - defn.ScalaValueClasses.map(x => x.requiredMethod(nme.getClass_)) + interceptedMethods = poundPoundMethods ++ Any_comparisons + primitiveGetClassMethods = Set[Symbol]() ++ defn.ScalaValueClasses.map(x => x.requiredMethod(nme.getClass_)) } // this should be removed if we have guarantee that ## will get Apply node @@ -97,7 +99,7 @@ class InterceptedMethods extends TreeTransform { override def transformApply(tree: Apply)(implicit ctx: Context, info: TransformerInfo): Tree = { def unknown = { - assert(false, s"The symbol '${tree.fun.symbol}' was interecepted but didn't match any cases, " + + assert(false, s"The symbol '${tree.fun.symbol.showLocated}' was intercepted but didn't match any cases, " + s"that means the intercepted methods set doesn't match the code") tree } @@ -109,9 +111,9 @@ class InterceptedMethods extends TreeTransform { PoundPoundValue(qual) } else if (Any_comparisons contains tree.fun.symbol.asTerm) { if (tree.fun.symbol eq defn.Any_==) { - Apply(Select(qual, defn.Object_equals.termRef), tree.args) + Apply(Select(qual, defn.Any_equals), tree.args) } else if (tree.fun.symbol eq defn.Any_!=) { - Select(Apply(Select(qual, defn.Object_equals.termRef), tree.args), defn.Boolean_!.termRef) + Select(Apply(Select(qual, defn.Any_equals), tree.args), defn.Boolean_!) } else unknown } /* else if (isPrimitiveValueClass(qual.tpe.typeSymbol)) { // todo: this is needed to support value classes @@ -128,7 +130,7 @@ class InterceptedMethods extends TreeTransform { // we get a primitive form of _getClass trying to target a boxed value // so we need replace that method name with Object_getClass to get correct behavior. // See SI-5568. - Apply(Select(qual, defn.Object_getClass.termRef), Nil) + Apply(Select(qual, defn.Any_getClass), Nil) } else { unknown } diff --git a/src/dotty/tools/dotc/transform/LazyVals.scala b/src/dotty/tools/dotc/transform/LazyVals.scala index 9e5ddffa4249..527c7e228965 100644 --- a/src/dotty/tools/dotc/transform/LazyVals.scala +++ b/src/dotty/tools/dotc/transform/LazyVals.scala @@ -54,7 +54,7 @@ class LazyValTranformContext { val infoTransformerNewDefinitions = mutable.Map.empty[ClassSymbol, ListBuffer[Symbol]] - def addSym(owner: ClassSymbol, sym: Symbol) { + def addSym(owner: ClassSymbol, sym: Symbol) = { infoTransformerNewDefinitions.get(owner) match { case Some(x) => x += sym case None => infoTransformerNewDefinitions.put(owner, ListBuffer(sym)) diff --git a/src/dotty/tools/dotc/transform/TailRec.scala b/src/dotty/tools/dotc/transform/TailRec.scala index b0d5c643834d..cd0643a6e7fe 100644 --- a/src/dotty/tools/dotc/transform/TailRec.scala +++ b/src/dotty/tools/dotc/transform/TailRec.scala @@ -129,7 +129,7 @@ class TailRec extends TreeTransform with DenotTransformer { Block( List(res), vparamss0.foldLeft(Apply(call, List(This(owner)))) - {case (call, args) => Apply(call, args.map(x=> Ident(x.symbol.termRef)))} + {(call, args) => Apply(call, args.map(x => Ident(x.symbol.termRef)))} ) } else { @@ -213,7 +213,8 @@ class TailRec extends TreeTransform with DenotTransformer { val methodWithTargs = if (targs.nonEmpty) TypeApply(method, targs) else method if (methodWithTargs.tpe.widen.isParameterless) methodWithTargs else argumentss.foldLeft(methodWithTargs) { - case (method, args) => Apply(method, args) + // case (method, args) => Apply(method, args) // Dotty deviation no auto-detupling yet. Interesting that one can do it in Scala2! + (method, args) => Apply(method, args) } } def fail(reason: String) = { @@ -229,7 +230,7 @@ class TailRec extends TreeTransform with DenotTransformer { val recv = noTailTransform(reciever) if (recv.tpe.widen.isParameterless) method else argumentss.foldLeft(Apply(method, List(recv))) { - case (method, args) => Apply(method, args) + (method, args) => Apply(method, args) // Dotty deviation no auto-detupling yet. } } diff --git a/src/dotty/tools/dotc/transform/TreeChecker.scala b/src/dotty/tools/dotc/transform/TreeChecker.scala index f52c5bc1c94d..e9970e1f88f3 100644 --- a/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -8,14 +8,17 @@ import core.SymDenotations._ import core.Contexts._ import core.Symbols._ import core.Types._ +import core.Flags._ import core.Constants._ import core.StdNames._ import core.Decorators._ import core.transform.Erasure.isUnboundedGeneric import typer._ import typer.ErrorReporting._ +import reporting.ThrowingReporter import ast.Trees._ import ast.{tpd, untpd} +import java.lang.AssertionError /** This transform eliminates patterns. Right now it's a dummy. * Awaiting the real pattern matcher. @@ -25,38 +28,69 @@ class TreeChecker { def check(ctx: Context) = { println(s"checking ${ctx.compilationUnit} after phase ${ctx.phase.prev}") - Checker.typedExpr(ctx.compilationUnit.tpdTree)(ctx) + val checkingCtx = ctx.fresh + .setTyperState(ctx.typerState.withReporter(new ThrowingReporter(ctx.typerState.reporter))) + Checker.typedExpr(ctx.compilationUnit.tpdTree)(checkingCtx) } object Checker extends ReTyper { - override def typed(tree: untpd.Tree, pt: Type)(implicit ctx: Context) = - if (tree.isEmpty) tree.asInstanceOf[Tree] - else { - assert(tree.hasType, tree.show) - val tree1 = super.typed(tree, pt) - def sameType(tp1: Type, tp2: Type) = - (tp1 eq tp2) || // accept NoType / NoType - (tp1 =:= tp2) - def divergenceMsg = - s"""Types differ - |Original type : ${tree.typeOpt.show} - |After checking: ${tree1.tpe.show} - |Original tree : ${tree.show} - |After checking: ${tree1.show} - """.stripMargin - assert(sameType(tree1.tpe, tree.typeOpt), divergenceMsg) - tree1 - } + override def typed(tree: untpd.Tree, pt: Type)(implicit ctx: Context) = try { + tree match { + case _: untpd.UnApply => + // can't recheck patterns + tree.asInstanceOf[tpd.Tree] + case _: untpd.TypedSplice | _: untpd.Thicket | _: EmptyValDef[_] => + super.typed(tree) + case _ if tree.isType => + promote(tree) + case _ => + val tree1 = super.typed(tree, pt) + def sameType(tp1: Type, tp2: Type) = + (tp1 eq tp2) || // accept NoType / NoType + (tp1 =:= tp2) + def divergenceMsg = + s"""Types differ + |Original type : ${tree.typeOpt.show} + |After checking: ${tree1.tpe.show} + |Original tree : ${tree.show} + |After checking: ${tree1.show} + """.stripMargin + assert(sameType(tree1.tpe, tree.typeOpt), divergenceMsg) + tree1 + } + } catch { + case ex: Throwable => + println(i"exception while checking $tree of class ${tree.getClass} # ${tree.uniqueId}") + throw ex + } override def typedIdent(tree: untpd.Ident, pt: Type)(implicit ctx: Context): Tree = { - assert(tree.isTerm, tree.show) + assert(tree.isTerm || ctx.phase.prev.id <= ctx.typerPhase.id, tree.show + " at " + ctx.phase) super.typedIdent(tree, pt) } override def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = { - assert(tree.isTerm, tree.show) + assert(tree.isTerm || ctx.phase.prev.id <= ctx.typerPhase.id, tree.show + " at " + ctx.phase) super.typedSelect(tree, pt) } + + /** Check that all defined symbols have legal owners. + * An owner is legal if it is either the same as the context's owner + * or there's an owner chain of valdefs starting at the context's owner and + * reaching up to the symbol's owner. The reason for this relaxed matching + * is that we should be able to pull out an expression as an initializer + * of a helper value without having to do a change owner traversal of the expression. + */ + override def index(trees: List[untpd.Tree])(implicit ctx: Context): Context = { + def ownerMatches(symOwner: Symbol, ctxOwner: Symbol): Boolean = + symOwner == ctxOwner || + ctxOwner.isTerm && !(ctxOwner is Method | Lazy | Mutable) && + ownerMatches(symOwner, ctxOwner.owner) + for (tree <- trees if tree.isDef) + assert(ownerMatches(tree.symbol.owner, ctx.owner), + i"bad owner; $tree has owner ${tree.symbol.owner}, expected was ${ctx.owner}") + super.index(trees) + } } } diff --git a/src/dotty/tools/dotc/transform/TreeTransform.scala b/src/dotty/tools/dotc/transform/TreeTransform.scala index c0ce68e95469..1bce0de66b57 100644 --- a/src/dotty/tools/dotc/transform/TreeTransform.scala +++ b/src/dotty/tools/dotc/transform/TreeTransform.scala @@ -886,32 +886,33 @@ object TreeTransforms { final private[TreeTransforms] def transformNamed(tree: NameTree, info: TransformerInfo, cur: Int)(implicit ctx: Context): Tree = tree match { case tree: Ident => - implicit val mutatedInfo = mutateTransformers(info, prepForIdent, info.nx.nxPrepIdent, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForIdent, info.nx.nxPrepIdent, tree, cur) + // Dotty deviation: implicits need explicit type if (mutatedInfo eq null) tree else goIdent(tree, mutatedInfo.nx.nxTransIdent(cur)) case tree: Select => - implicit val mutatedInfo = mutateTransformers(info, prepForSelect, info.nx.nxPrepSelect, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForSelect, info.nx.nxPrepSelect, tree, cur) if (mutatedInfo eq null) tree else { val qual = transform(tree.qualifier, mutatedInfo, cur) goSelect(cpy.Select(tree, qual, tree.name), mutatedInfo.nx.nxTransSelect(cur)) } case tree: SelectFromTypeTree => - implicit val mutatedInfo = mutateTransformers(info, prepForSelectFromTypeTree, info.nx.nxPrepSelectFromTypeTree, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForSelectFromTypeTree, info.nx.nxPrepSelectFromTypeTree, tree, cur) if (mutatedInfo eq null) tree else { val qual = transform(tree.qualifier, mutatedInfo, cur) goSelectFromTypeTree(cpy.SelectFromTypeTree(tree, qual, tree.name), mutatedInfo.nx.nxTransSelectFromTypeTree(cur)) } case tree: Bind => - implicit val mutatedInfo = mutateTransformers(info, prepForBind, info.nx.nxPrepBind, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForBind, info.nx.nxPrepBind, tree, cur) if (mutatedInfo eq null) tree else { val body = transform(tree.body, mutatedInfo, mutatedInfo.nx.nxTransBind(cur)) goBind(cpy.Bind(tree, tree.name, body), cur) } case tree: ValDef if !tree.isEmpty => // As a result of discussing with Martin: emptyValDefs shouldn't be copied // NAME - implicit val mutatedInfo = mutateTransformers(info, prepForValDef, info.nx.nxPrepValDef, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForValDef, info.nx.nxPrepValDef, tree, cur) if (mutatedInfo eq null) tree else { val nestedCtx = if (tree.symbol.exists) localContext(tree.symbol) else ctx @@ -920,7 +921,7 @@ object TreeTransforms { goValDef(cpy.ValDef(tree, tree.mods, tree.name, tpt, rhs), mutatedInfo.nx.nxTransValDef(cur)) } case tree: DefDef => - implicit val mutatedInfo = mutateTransformers(info, prepForDefDef, info.nx.nxPrepDefDef, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForDefDef, info.nx.nxPrepDefDef, tree, cur) if (mutatedInfo eq null) tree else { val nestedCtx = localContext(tree.symbol) @@ -931,7 +932,7 @@ object TreeTransforms { goDefDef(cpy.DefDef(tree, tree.mods, tree.name, tparams, vparams, tpt, rhs), mutatedInfo.nx.nxTransDefDef(cur)) } case tree: TypeDef => - implicit val mutatedInfo = mutateTransformers(info, prepForTypeDef, info.nx.nxPrepTypeDef, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTypeDef, info.nx.nxPrepTypeDef, tree, cur) if (mutatedInfo eq null) tree else { val rhs = transform(tree.rhs, mutatedInfo, cur)(localContext(tree.symbol)) @@ -944,18 +945,18 @@ object TreeTransforms { final private[TreeTransforms] def transformUnnamed(tree: Tree, info: TransformerInfo, cur: Int)(implicit ctx: Context): Tree = tree match { case tree: This => - implicit val mutatedInfo = mutateTransformers(info, prepForThis, info.nx.nxPrepThis, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForThis, info.nx.nxPrepThis, tree, cur) if (mutatedInfo eq null) tree else goThis(tree, mutatedInfo.nx.nxTransThis(cur)) case tree: Super => - implicit val mutatedInfo = mutateTransformers(info, prepForSuper, info.nx.nxPrepSuper, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForSuper, info.nx.nxPrepSuper, tree, cur) if (mutatedInfo eq null) tree else { val qual = transform(tree.qual, mutatedInfo, cur) goSuper(cpy.Super(tree, qual, tree.mix), mutatedInfo.nx.nxTransSuper(cur)) } case tree: Apply => - implicit val mutatedInfo = mutateTransformers(info, prepForApply, info.nx.nxPrepApply, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForApply, info.nx.nxPrepApply, tree, cur) if (mutatedInfo eq null) tree else { val fun = transform(tree.fun, mutatedInfo, cur) @@ -963,7 +964,7 @@ object TreeTransforms { goApply(cpy.Apply(tree, fun, args), mutatedInfo.nx.nxTransApply(cur)) } case tree: TypeApply => - implicit val mutatedInfo = mutateTransformers(info, prepForTypeApply, info.nx.nxPrepTypeApply, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTypeApply, info.nx.nxPrepTypeApply, tree, cur) if (mutatedInfo eq null) tree else { val fun = transform(tree.fun, mutatedInfo, cur) @@ -971,18 +972,18 @@ object TreeTransforms { goTypeApply(cpy.TypeApply(tree, fun, args), mutatedInfo.nx.nxTransTypeApply(cur)) } case tree: Literal => - implicit val mutatedInfo = mutateTransformers(info, prepForLiteral, info.nx.nxPrepLiteral, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForLiteral, info.nx.nxPrepLiteral, tree, cur) if (mutatedInfo eq null) tree else goLiteral(tree, mutatedInfo.nx.nxTransLiteral(cur)) case tree: New => - implicit val mutatedInfo = mutateTransformers(info, prepForNew, info.nx.nxPrepNew, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForNew, info.nx.nxPrepNew, tree, cur) if (mutatedInfo eq null) tree else { val tpt = transform(tree.tpt, mutatedInfo, cur) goNew(cpy.New(tree, tpt), mutatedInfo.nx.nxTransNew(cur)) } case tree: Pair => - implicit val mutatedInfo = mutateTransformers(info, prepForPair, info.nx.nxPrepPair, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForPair, info.nx.nxPrepPair, tree, cur) if (mutatedInfo eq null) tree else { val left = transform(tree.left, mutatedInfo, cur) @@ -990,7 +991,7 @@ object TreeTransforms { goPair(cpy.Pair(tree, left, right), mutatedInfo.nx.nxTransPair(cur)) } case tree: Typed => - implicit val mutatedInfo = mutateTransformers(info, prepForTyped, info.nx.nxPrepTyped, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTyped, info.nx.nxPrepTyped, tree, cur) if (mutatedInfo eq null) tree else { val expr = transform(tree.expr, mutatedInfo, cur) @@ -998,7 +999,7 @@ object TreeTransforms { goTyped(cpy.Typed(tree, expr, tpt), mutatedInfo.nx.nxTransTyped(cur)) } case tree: Assign => - implicit val mutatedInfo = mutateTransformers(info, prepForAssign, info.nx.nxPrepAssign, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForAssign, info.nx.nxPrepAssign, tree, cur) if (mutatedInfo eq null) tree else { val lhs = transform(tree.lhs, mutatedInfo, cur) @@ -1006,7 +1007,7 @@ object TreeTransforms { goAssign(cpy.Assign(tree, lhs, rhs), mutatedInfo.nx.nxTransAssign(cur)) } case tree: Block => - implicit val mutatedInfo = mutateTransformers(info, prepForBlock, info.nx.nxPrepBlock, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForBlock, info.nx.nxPrepBlock, tree, cur) if (mutatedInfo eq null) tree else { val stats = transformStats(tree.stats, ctx.owner, mutatedInfo, cur) @@ -1014,7 +1015,7 @@ object TreeTransforms { goBlock(cpy.Block(tree, stats, expr), mutatedInfo.nx.nxTransBlock(cur)) } case tree: If => - implicit val mutatedInfo = mutateTransformers(info, prepForIf, info.nx.nxPrepIf, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForIf, info.nx.nxPrepIf, tree, cur) if (mutatedInfo eq null) tree else { val cond = transform(tree.cond, mutatedInfo, cur) @@ -1023,7 +1024,7 @@ object TreeTransforms { goIf(cpy.If(tree, cond, thenp, elsep), mutatedInfo.nx.nxTransIf(cur)) } case tree: Closure => - implicit val mutatedInfo = mutateTransformers(info, prepForClosure, info.nx.nxPrepClosure, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForClosure, info.nx.nxPrepClosure, tree, cur) if (mutatedInfo eq null) tree else { val env = transformTrees(tree.env, mutatedInfo, cur) @@ -1032,7 +1033,7 @@ object TreeTransforms { goClosure(cpy.Closure(tree, env, meth, tpt), mutatedInfo.nx.nxTransClosure(cur)) } case tree: Match => - implicit val mutatedInfo = mutateTransformers(info, prepForMatch, info.nx.nxPrepMatch, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForMatch, info.nx.nxPrepMatch, tree, cur) if (mutatedInfo eq null) tree else { val selector = transform(tree.selector, mutatedInfo, cur) @@ -1040,7 +1041,7 @@ object TreeTransforms { goMatch(cpy.Match(tree, selector, cases), mutatedInfo.nx.nxTransMatch(cur)) } case tree: CaseDef => - implicit val mutatedInfo = mutateTransformers(info, prepForCaseDef, info.nx.nxPrepCaseDef, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForCaseDef, info.nx.nxPrepCaseDef, tree, cur) if (mutatedInfo eq null) tree else { val pat = transform(tree.pat, mutatedInfo, cur) @@ -1049,7 +1050,7 @@ object TreeTransforms { goCaseDef(cpy.CaseDef(tree, pat, guard, body), mutatedInfo.nx.nxTransCaseDef(cur)) } case tree: Return => - implicit val mutatedInfo = mutateTransformers(info, prepForReturn, info.nx.nxPrepReturn, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForReturn, info.nx.nxPrepReturn, tree, cur) if (mutatedInfo eq null) tree else { val expr = transform(tree.expr, mutatedInfo, cur) @@ -1057,7 +1058,7 @@ object TreeTransforms { goReturn(cpy.Return(tree, expr, from), mutatedInfo.nx.nxTransReturn(cur)) } case tree: Try => - implicit val mutatedInfo = mutateTransformers(info, prepForTry, info.nx.nxPrepTry, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTry, info.nx.nxPrepTry, tree, cur) if (mutatedInfo eq null) tree else { val block = transform(tree.expr, mutatedInfo, cur) @@ -1066,35 +1067,35 @@ object TreeTransforms { goTry(cpy.Try(tree, block, handler, finalizer), mutatedInfo.nx.nxTransTry(cur)) } case tree: Throw => - implicit val mutatedInfo = mutateTransformers(info, prepForThrow, info.nx.nxPrepThrow, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForThrow, info.nx.nxPrepThrow, tree, cur) if (mutatedInfo eq null) tree else { val expr = transform(tree.expr, mutatedInfo, cur) goThrow(cpy.Throw(tree, expr), mutatedInfo.nx.nxTransThrow(cur)) } case tree: SeqLiteral => - implicit val mutatedInfo = mutateTransformers(info, prepForSeqLiteral, info.nx.nxPrepSeqLiteral, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForSeqLiteral, info.nx.nxPrepSeqLiteral, tree, cur) if (mutatedInfo eq null) tree else { val elems = transformTrees(tree.elems, mutatedInfo, cur) goSeqLiteral(cpy.SeqLiteral(tree, elems), mutatedInfo.nx.nxTransLiteral(cur)) } case tree: TypeTree => - implicit val mutatedInfo = mutateTransformers(info, prepForTypeTree, info.nx.nxPrepTypeTree, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTypeTree, info.nx.nxPrepTypeTree, tree, cur) if (mutatedInfo eq null) tree else { val original = transform(tree.original, mutatedInfo, cur) goTypeTree(cpy.TypeTree(tree, original), mutatedInfo.nx.nxTransTypeTree(cur)) } case tree: Alternative => - implicit val mutatedInfo = mutateTransformers(info, prepForAlternative, info.nx.nxPrepAlternative, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForAlternative, info.nx.nxPrepAlternative, tree, cur) if (mutatedInfo eq null) tree else { val trees = transformTrees(tree.trees, mutatedInfo, cur) goAlternative(cpy.Alternative(tree, trees), mutatedInfo.nx.nxTransAlternative(cur)) } case tree: UnApply => - implicit val mutatedInfo = mutateTransformers(info, prepForUnApply, info.nx.nxPrepUnApply, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForUnApply, info.nx.nxPrepUnApply, tree, cur) if (mutatedInfo eq null) tree else { val fun = transform(tree.fun, mutatedInfo, cur) @@ -1103,7 +1104,7 @@ object TreeTransforms { goUnApply(cpy.UnApply(tree, fun, implicits, patterns), mutatedInfo.nx.nxTransUnApply(cur)) } case tree: Template => - implicit val mutatedInfo = mutateTransformers(info, prepForTemplate, info.nx.nxPrepTemplate, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForTemplate, info.nx.nxPrepTemplate, tree, cur) if (mutatedInfo eq null) tree else { val constr = transformSub(tree.constr, mutatedInfo, cur) @@ -1113,7 +1114,7 @@ object TreeTransforms { goTemplate(cpy.Template(tree, constr, parents, self, body), mutatedInfo.nx.nxTransTemplate(cur)) } case tree: PackageDef => - implicit val mutatedInfo = mutateTransformers(info, prepForPackageDef, info.nx.nxPrepPackageDef, tree, cur) + implicit val mutatedInfo: TransformerInfo = mutateTransformers(info, prepForPackageDef, info.nx.nxPrepPackageDef, tree, cur) if (mutatedInfo eq null) tree else { val nestedCtx = localContext(tree.symbol) diff --git a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala index a36bf6500c40..5f65ee414806 100644 --- a/src/dotty/tools/dotc/transform/TypeTestsCasts.scala +++ b/src/dotty/tools/dotc/transform/TypeTestsCasts.scala @@ -68,10 +68,10 @@ class TypeTestsCasts extends TreeTransform { runtimeCall(nme.isArray, arg :: Literal(Constant(ndims)) :: Nil) if (ndims == 1) isArrayTest(qual) else evalOnce(qual) { qual1 => - mkAnd(derivedTree(qual1, defn.Object_isInstanceOf, qual1.tpe), isArrayTest(qual1)) + mkAnd(derivedTree(qual1, defn.Any_isInstanceOf, qual1.tpe), isArrayTest(qual1)) } case _ => - derivedTree(expr, defn.Object_isInstanceOf, argType) + derivedTree(expr, defn.Any_isInstanceOf, argType) } } @@ -81,10 +81,10 @@ class TypeTestsCasts extends TreeTransform { else if (qualCls.isPrimitiveValueClass) { val argCls = argType.classSymbol if (argCls.isPrimitiveValueClass) primitiveConversion(qual, argCls) - else derivedTree(box(qual), defn.Object_asInstanceOf, argType) + else derivedTree(box(qual), defn.Any_asInstanceOf, argType) } else - derivedTree(qual, defn.Object_asInstanceOf, argType) + derivedTree(qual, defn.Any_asInstanceOf, argType) } if (sym eq defn.Any_isInstanceOf) diff --git a/src/dotty/tools/dotc/typer/Checking.scala b/src/dotty/tools/dotc/typer/Checking.scala index ae325af2a449..5e52c5d7e0cd 100644 --- a/src/dotty/tools/dotc/typer/Checking.scala +++ b/src/dotty/tools/dotc/typer/Checking.scala @@ -69,15 +69,6 @@ trait Checking { defn.ObjectClass.typeRef } - /** Check that (return) type of implicit definition is not empty */ - def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = defTree.tpt match { - case tpt: untpd.DerivedTypeTree => - case TypeTree(untpd.EmptyTree) => - val resStr = if (defTree.isInstanceOf[untpd.DefDef]) "result " else "" - ctx.error(d"${resStr}type of implicit definition needs to be given explicitly", defTree.pos) - case _ => - } - /** Check that a non-implicit parameter making up the first parameter section of an * implicit conversion is not a singleton type. */ @@ -150,7 +141,6 @@ trait NoChecking extends Checking { override def checkStable(tp: Type, pos: Position)(implicit ctx: Context): Unit = () override def checkLegalPrefix(tp: Type, pos: Position)(implicit ctx: Context): Unit = () override def checkClassTypeWithStablePrefix(tp: Type, pos: Position, traitReq: Boolean)(implicit ctx: Context): Type = tp - override def checkImplicitTptNonEmpty(defTree: untpd.ValOrDefDef)(implicit ctx: Context): Unit = () override def checkImplicitParamsNotSingletons(vparamss: List[List[ValDef]])(implicit ctx: Context): Unit = () override def checkFeasible(tp: Type, pos: Position, where: => String = "")(implicit ctx: Context): Type = tp override def checkNoDoubleDefs(cls: Symbol)(implicit ctx: Context): Unit = () diff --git a/src/dotty/tools/dotc/typer/EtaExpansion.scala b/src/dotty/tools/dotc/typer/EtaExpansion.scala index 099dd943a608..110dc6152932 100644 --- a/src/dotty/tools/dotc/typer/EtaExpansion.scala +++ b/src/dotty/tools/dotc/typer/EtaExpansion.scala @@ -116,6 +116,7 @@ object EtaExpansion { */ def etaExpand(tree: Tree, mt: MethodType, xarity: Int)(implicit ctx: Context): untpd.Tree = { import untpd._ + assert(!ctx.isAfterTyper) val defs = new mutable.ListBuffer[tpd.Tree] val lifted: Tree = TypedSplice(liftApp(defs, tree)) val paramTypes: List[Tree] = diff --git a/src/dotty/tools/dotc/typer/Implicits.scala b/src/dotty/tools/dotc/typer/Implicits.scala index 93876651ac80..a32f552edf51 100644 --- a/src/dotty/tools/dotc/typer/Implicits.scala +++ b/src/dotty/tools/dotc/typer/Implicits.scala @@ -65,7 +65,7 @@ object Implicits { case tpw => //if (ctx.typer.isApplicable(tp, argType :: Nil, resultType)) // println(i"??? $tp is applicable to $this / typeSymbol = ${tpw.typeSymbol}") - !tpw.derivesFrom(defn.FunctionClass(1)) + !tpw.derivesFrom(defn.FunctionClass(1)) || tpw.isRef(defn.PredefConformsClass) } def discardForValueType(tpw: Type): Boolean = tpw match { @@ -400,6 +400,9 @@ trait Implicits { self: Typer => * !!! todo: catch potential cycles */ def inferImplicit(pt: Type, argument: Tree, pos: Position)(implicit ctx: Context): SearchResult = track("inferImplicit") { + assert(!ctx.isAfterTyper, + if (argument.isEmpty) i"missing implicit parameter of type $pt after typer" + else i"type error: ${argument.tpe} does not conform to $pt") ctx.traceIndented(s"search implicit ${pt.show}, arg = ${argument.show}: ${argument.tpe.show}", implicits, show = true) { assert(!pt.isInstanceOf[ExprType]) val isearch = @@ -472,7 +475,7 @@ trait Implicits { self: Typer => shadowedImplicit(ref, methPart(shadowing).tpe) } else - SearchSuccess(generated, ref, ctx.typerState) + SearchSuccess(generated1, ref, ctx.typerState) }} /** Given a list of implicit references, produce a list of all implicit search successes, diff --git a/src/dotty/tools/dotc/typer/Namer.scala b/src/dotty/tools/dotc/typer/Namer.scala index 2d4bf809951c..c3f1dcc81997 100644 --- a/src/dotty/tools/dotc/typer/Namer.scala +++ b/src/dotty/tools/dotc/typer/Namer.scala @@ -519,80 +519,92 @@ class Namer { typer: Typer => * defined symbol, given its final return type */ def valOrDefDefSig(mdef: ValOrDefDef, sym: Symbol, typeParams: List[Symbol], paramFn: Type => Type)(implicit ctx: Context): Type = { - val pt = - if (!mdef.tpt.isEmpty) WildcardType - else { - /** An type for this definition that might be inherited from elsewhere: - * If this is a setter parameter, the corresponding getter type. - * If this is a class member, the conjunction of all result types - * of overridden methods. - * NoType if neither case holds. - */ - val inherited = - if (sym.owner.isTerm) NoType - else { - // TODO: Look only at member of supertype instead? - lazy val schema = paramFn(WildcardType) - val site = sym.owner.thisType - ((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) => - val iRawInfo = - cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema).info - val iInstInfo = iRawInfo match { - case iRawInfo: PolyType => - if (iRawInfo.paramNames.length == typeParams.length) - iRawInfo.instantiate(typeParams map (_.typeRef)) - else NoType - case _ => - if (typeParams.isEmpty) iRawInfo - else NoType - } - val iResType = iInstInfo.finalResultType.asSeenFrom(site, cls) - if (iResType.exists) - typr.println(s"using inherited type; raw: $iRawInfo, inst: $iInstInfo, inherited: $iResType") - tp & iResType + def inferredType = { + /** A type for this definition that might be inherited from elsewhere: + * If this is a setter parameter, the corresponding getter type. + * If this is a class member, the conjunction of all result types + * of overridden methods. + * NoType if neither case holds. + */ + val inherited = + if (sym.owner.isTerm) NoType + else { + // TODO: Look only at member of supertype instead? + lazy val schema = paramFn(WildcardType) + val site = sym.owner.thisType + ((NoType: Type) /: sym.owner.info.baseClasses.tail) { (tp, cls) => + val iRawInfo = + cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema).info + val iInstInfo = iRawInfo match { + case iRawInfo: PolyType => + if (iRawInfo.paramNames.length == typeParams.length) + iRawInfo.instantiate(typeParams map (_.typeRef)) + else NoType + case _ => + if (typeParams.isEmpty) iRawInfo + else NoType } + val iResType = iInstInfo.finalResultType.asSeenFrom(site, cls) + if (iResType.exists) + typr.println(s"using inherited type; raw: $iRawInfo, inst: $iInstInfo, inherited: $iResType") + tp & iResType } + } - /** The proto-type to be used when inferring the result type from - * the right hand side. This is `WildcardType` except if the definition - * is a default getter. In that case, the proto-type is the type of - * the corresponding parameter where bound parameters are replaced by - * Wildcards. - */ - def rhsProto = { - val name = sym.asTerm.name - val idx = name.defaultGetterIndex - if (idx < 0) WildcardType - else { - val original = name.defaultGetterToMethod - val meth: Denotation = - if (original.isConstructorName && (sym.owner is ModuleClass)) - sym.owner.companionClass.info.decl(nme.CONSTRUCTOR) - else - ctx.defContext(sym).denotNamed(original) - def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match { - case params :: paramss1 => - if (idx < params.length) wildApprox(params(idx)) - else paramProto(paramss1, idx - params.length) - case nil => - WildcardType - } - val defaultAlts = meth.altsWith(_.hasDefaultParams) - if (defaultAlts.length == 1) - paramProto(defaultAlts.head.info.widen.paramTypess, idx) + /** The proto-type to be used when inferring the result type from + * the right hand side. This is `WildcardType` except if the definition + * is a default getter. In that case, the proto-type is the type of + * the corresponding parameter where bound parameters are replaced by + * Wildcards. + */ + def rhsProto = { + val name = sym.asTerm.name + val idx = name.defaultGetterIndex + if (idx < 0) WildcardType + else { + val original = name.defaultGetterToMethod + val meth: Denotation = + if (original.isConstructorName && (sym.owner is ModuleClass)) + sym.owner.companionClass.info.decl(nme.CONSTRUCTOR) else + ctx.defContext(sym).denotNamed(original) + def paramProto(paramss: List[List[Type]], idx: Int): Type = paramss match { + case params :: paramss1 => + if (idx < params.length) wildApprox(params(idx)) + else paramProto(paramss1, idx - params.length) + case nil => WildcardType } + val defaultAlts = meth.altsWith(_.hasDefaultParams) + if (defaultAlts.length == 1) + paramProto(defaultAlts.head.info.widen.paramTypess, idx) + else + WildcardType } + } - // println(s"final inherited for $sym: ${inherited.toString}") !!! - // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}") - val rhsCtx = ctx.fresh addMode Mode.InferringReturnType - def rhsType = typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion - def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos) - inherited orElse lhsType orElse WildcardType + // println(s"final inherited for $sym: ${inherited.toString}") !!! + // println(s"owner = ${sym.owner}, decls = ${sym.owner.info.decls.show}") + val rhsCtx = ctx.fresh addMode Mode.InferringReturnType + def rhsType = typedAheadExpr(mdef.rhs, rhsProto)(rhsCtx).tpe.widen.approximateUnion + def lhsType = fullyDefinedType(rhsType, "right-hand side", mdef.pos) + if (inherited.exists) inherited + else { + if (sym is Implicit) { + val resStr = if (mdef.isInstanceOf[DefDef]) "result " else "" + ctx.error(d"${resStr}type of implicit definition needs to be given explicitly", mdef.pos) + sym.resetFlag(Implicit) + } + lhsType orElse WildcardType } + } + + val pt = mdef.tpt match { + case _: untpd.DerivedTypeTree => WildcardType + case TypeTree(untpd.EmptyTree) => inferredType + case _ => WildcardType + } paramFn(typedAheadType(mdef.tpt, pt).tpe) } diff --git a/src/dotty/tools/dotc/typer/ProtoTypes.scala b/src/dotty/tools/dotc/typer/ProtoTypes.scala index aeba02648da1..4aba4fb59ac4 100644 --- a/src/dotty/tools/dotc/typer/ProtoTypes.scala +++ b/src/dotty/tools/dotc/typer/ProtoTypes.scala @@ -46,7 +46,7 @@ object ProtoTypes { * fits the given expected result type. */ def constrainResult(mt: Type, pt: Type)(implicit ctx: Context): Boolean = pt match { - case FunProto(_, result, _) => + case _: FunProto => mt match { case mt: MethodType => mt.isDependent || constrainResult(mt.resultType, pt.resultType) @@ -60,6 +60,8 @@ object ProtoTypes { case _ => isCompatible(mt, pt) } + case _: WildcardType => + isCompatible(mt, pt) case _ => true } @@ -217,9 +219,8 @@ object ProtoTypes { */ abstract case class ViewProto(argType: Type, override val resultType: Type)(implicit ctx: Context) extends CachedGroundType with ApplyingProto { - def isMatchedBy(tp: Type)(implicit ctx: Context): Boolean = /*ctx.conditionalTraceIndented(lookingForInfo, i"?.info isMatchedBy $tp ${tp.getClass}")*/ { + def isMatchedBy(tp: Type)(implicit ctx: Context): Boolean = ctx.typer.isApplicable(tp, argType :: Nil, resultType) - } def derivedViewProto(argType: Type, resultType: Type)(implicit ctx: Context) = if ((argType eq this.argType) && (resultType eq this.resultType)) this @@ -352,17 +353,15 @@ object ProtoTypes { tp.derivedRefinedType(wildApprox(tp.parent, theMap), tp.refinedName, wildApprox(tp.refinedInfo, theMap)) case tp: TypeBounds if tp.lo eq tp.hi => // default case, inlined for speed tp.derivedTypeAlias(wildApprox(tp.lo, theMap)) - case PolyParam(pt, pnum) => - WildcardType(wildApprox(pt.paramBounds(pnum)).bounds) + case tp @ PolyParam(poly, pnum) => + ctx.typerState.constraint.at(tp) match { + case bounds: TypeBounds => wildApprox(WildcardType(bounds)) + case _ => WildcardType(wildApprox(poly.paramBounds(pnum)).bounds) + } case MethodParam(mt, pnum) => WildcardType(TypeBounds.upper(wildApprox(mt.paramTypes(pnum)))) case tp: TypeVar => - val inst = tp.instanceOpt - if (inst.exists) wildApprox(inst) - else ctx.typerState.constraint.at(tp.origin) match { - case bounds: TypeBounds => wildApprox(WildcardType(bounds)) - case NoType => WildcardType - } + wildApprox(tp.underlying) case tp: AndType => val tp1a = wildApprox(tp.tp1) val tp2a = wildApprox(tp.tp2) diff --git a/src/dotty/tools/dotc/typer/ReTyper.scala b/src/dotty/tools/dotc/typer/ReTyper.scala index c2f627b1e7b9..76817fd16cb6 100644 --- a/src/dotty/tools/dotc/typer/ReTyper.scala +++ b/src/dotty/tools/dotc/typer/ReTyper.scala @@ -4,6 +4,7 @@ package typer import core.Contexts._ import core.Types._ import core.Symbols._ +import core.Decorators._ import typer.ProtoTypes._ import ast.{tpd, untpd} import ast.Trees._ @@ -20,7 +21,7 @@ class ReTyper extends Typer { import tpd._ protected def promote(tree: untpd.Tree)(implicit ctx: Context): tree.ThisTree[Type] = { - assert(tree.hasType) + assert(tree.hasType, i"$tree ${tree.getClass} ${tree.uniqueId}") tree.withType(tree.typeOpt) } @@ -39,6 +40,9 @@ class ReTyper extends Typer { untpd.cpy.SelectFromTypeTree(tree, qual1, tree.name).withType(tree.typeOpt) } + override def typedLiteral(tree: untpd.Literal)(implicit ctc: Context): Literal = + promote(tree) + override def typedTypeTree(tree: untpd.TypeTree, pt: Type)(implicit ctx: Context): TypeTree = promote(tree) diff --git a/src/dotty/tools/dotc/typer/TypeAssigner.scala b/src/dotty/tools/dotc/typer/TypeAssigner.scala index 12f2415d89da..13f65d42491f 100644 --- a/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -166,17 +166,14 @@ trait TypeAssigner { * - any further information it needs to access to compute that type. */ - def assignType(tree: untpd.Ident, rawType: Type)(implicit ctx: Context) = { - tree.withType(if (tree.isType) rawType else rawType.underlyingIfRepeated) - } + def assignType(tree: untpd.Ident, tp: Type)(implicit ctx: Context) = + tree.withType(tp) - def assignType(tree: untpd.Select, qual: Tree)(implicit ctx: Context) = { + def assignType(tree: untpd.Select, qual: Tree)(implicit ctx: Context) = tree.withType(accessibleSelectionType(tree, qual)) - } - def assignType(tree: untpd.SelectFromTypeTree, qual: Tree)(implicit ctx: Context) = { + def assignType(tree: untpd.SelectFromTypeTree, qual: Tree)(implicit ctx: Context) = tree.withType(accessibleSelectionType(tree, qual)) - } def assignType(tree: untpd.New, tpt: Tree)(implicit ctx: Context) = tree.withType(tpt.tpe) diff --git a/src/dotty/tools/dotc/typer/Typer.scala b/src/dotty/tools/dotc/typer/Typer.scala index e4acff53631d..f4b52ce09d16 100644 --- a/src/dotty/tools/dotc/typer/Typer.scala +++ b/src/dotty/tools/dotc/typer/Typer.scala @@ -260,7 +260,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit error(d"not found: $kind$name", tree.pos) ErrorType } - checkValue(tree.withType(ownType.underlyingIfRepeated), pt) + checkValue(tree.withType(ownType), pt) } def typedSelect(tree: untpd.Select, pt: Type)(implicit ctx: Context): Tree = track("typedSelect") { @@ -753,7 +753,6 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val ValDef(mods, name, tpt, rhs) = vdef val mods1 = typedModifiers(mods, sym) val tpt1 = typedType(tpt) - if ((sym is Implicit) && sym.owner.isType) checkImplicitTptNonEmpty(vdef) val rhs1 = rhs match { case Ident(nme.WILDCARD) => rhs withType tpt1.tpe case _ => typedExpr(rhs, tpt1.tpe) @@ -766,10 +765,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit val mods1 = typedModifiers(mods, sym) val tparams1 = tparams mapconserve (typed(_).asInstanceOf[TypeDef]) val vparamss1 = vparamss nestedMapconserve (typed(_).asInstanceOf[ValDef]) - if (sym is Implicit) { - if (sym.owner.isType) checkImplicitTptNonEmpty(ddef) - checkImplicitParamsNotSingletons(vparamss1) - } + if (sym is Implicit) checkImplicitParamsNotSingletons(vparamss1) val tpt1 = typedType(tpt) val rhs1 = typedExpr(rhs, tpt1.tpe) assignType(cpy.DefDef(ddef, mods1, name, tparams1, vparamss1, tpt1, rhs1), sym) @@ -1137,7 +1133,7 @@ class Typer extends Namer with TypeAssigner with Applications with Implicits wit def where = d"parameter $pname of $methodStr" inferImplicit(formal, EmptyTree, tree.pos.endPos) match { case SearchSuccess(arg, _, _) => - arg + adapt(arg, formal) case ambi: AmbiguousImplicits => implicitArgError(s"ambiguous implicits: ${ambi.explanation} of $where") case failure: SearchFailure => diff --git a/test/dotc/comptest.scala b/test/dotc/comptest.scala index e7f60488b89d..63c4003047f3 100644 --- a/test/dotc/comptest.scala +++ b/test/dotc/comptest.scala @@ -15,7 +15,7 @@ object comptest extends CompilerTest { dotcDir + "tools/dotc/ast/Trees.scala", "#runs", "2", "-Ylog:frontend", - "-Xprompt")) + "-Xprompt"))(Nil) // compileDir(dotcDir + "tools/dotc/printing", List("-Xprompt", "-Ylog:frontend", "#runs", "2", "-uniqid")) } diff --git a/test/dotc/tests.scala b/test/dotc/tests.scala index c6fbcabf4eb6..31ab15b57b91 100644 --- a/test/dotc/tests.scala +++ b/test/dotc/tests.scala @@ -5,15 +5,18 @@ import test._ class tests extends CompilerTest { - override val defaultOptions = - List( + val noCheckOptions = List( // "-verbose", // "-Ylog:frontend", // "-Xprompt", // "-explaintypes", // "-Yshow-suppressed-errors", - "-pagewidth", "160" - ) + "-pagewidth", "160") + + implicit val defaultOptions = noCheckOptions ++ List( + "-Ycheck:front"//, "-Ystop-before:terminal" + ) + val twice = List("#runs", "2", "-YnoDoubleBindings") val doErase = List("-Ystop-before:terminal") @@ -68,7 +71,10 @@ class tests extends CompilerTest { @Test def neg_i50_volatile = compileFile(negDir, "i50-volatile", xerrors = 4) @Test def neg_t0273_doubledefs = compileFile(negDir, "t0273", xerrors = 1) @Test def neg_t0586_structural = compileFile(negDir, "t0586", xerrors = 1) - @Test def neg_t0625_structural = compileFile(negDir, "t0625", xerrors = 1) + @Test def neg_t0625_structural = compileFile(negDir, "t0625", xerrors = 1)( + defaultOptions = noCheckOptions) + // -Ycheck fails because there are structural types involving higher-kinded types. + // these are illegal, but are tested only later. @Test def neg_t0654_polyalias = compileFile(negDir, "t0654", xerrors = 2) @Test def neg_t1192_legalPrefix = compileFile(negDir, "t1192", xerrors = 1) @Test def neg_tailcall_t1672b = compileFile(negDir, "tailcall/t1672b", xerrors = 6) @@ -83,7 +89,8 @@ class tests extends CompilerTest { @Test def dotc_config = compileDir(dotcDir + "tools/dotc/config", twice) @Test def dotc_core = compileDir(dotcDir + "tools/dotc/core", twice) @Test def dotc_core_pickling = compileDir(dotcDir + "tools/dotc/core/pickling", twice) - @Test def dotc_transform = compileDir(dotcDir + "tools/dotc/core/transform", twice) + @Test def dotc_core_transform = compileDir(dotcDir + "tools/dotc/core/transform", twice) + @Test def dotc_transform = compileDir(dotcDir + "tools/dotc/transform", twice) @Test def dotc_parsing = compileDir(dotcDir + "tools/dotc/parsing", twice) @Test def dotc_printing = compileDir(dotcDir + "tools/dotc/printing", twice) @Test def dotc_reporting = compileDir(dotcDir + "tools/dotc/reporting", twice) diff --git a/test/test/CompilerTest.scala b/test/test/CompilerTest.scala index d52e74de7b9e..1bf138d54920 100644 --- a/test/test/CompilerTest.scala +++ b/test/test/CompilerTest.scala @@ -8,29 +8,27 @@ import dotty.tools.dotc.reporting.Reporter class CompilerTest extends DottyTest { - def defaultOptions: List[String] = Nil - - def compileArgs(args: Array[String], xerrors: Int = 0): Unit = { + def compileArgs(args: Array[String], xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit = { val allArgs = args ++ defaultOptions val processor = if (allArgs.exists(_.startsWith("#"))) Bench else Main val nerrors = processor.process(allArgs, ctx).count(Reporter.ERROR.level) assert(nerrors == xerrors, s"Wrong # of errors. Expected: $xerrors, found: $nerrors") } - def compileLine(cmdLine: String, xerrors: Int = 0): Unit = compileArgs(cmdLine.split("\n"), xerrors) + def compileLine(cmdLine: String, xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit = compileArgs(cmdLine.split("\n"), xerrors) - def compileFile(prefix: String, fileName: String, args: List[String] = Nil, xerrors: Int = 0): Unit = + def compileFile(prefix: String, fileName: String, args: List[String] = Nil, xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit = compileArgs((s"$prefix$fileName.scala" :: args).toArray, xerrors) - def compileDir(path: String, args: List[String] = Nil, xerrors: Int = 0): Unit = + def compileDir(path: String, args: List[String] = Nil, xerrors: Int = 0)(implicit defaultOptions: List[String]): Unit = compileDir(Directory(path), args, xerrors) - def compileDir(dir: Directory, args: List[String], xerrors: Int): Unit = { + def compileDir(dir: Directory, args: List[String], xerrors: Int)(implicit defaultOptions: List[String]): Unit = { val fileNames = dir.files.toArray.map(_.toString).filter(_ endsWith ".scala") compileArgs(fileNames ++ args, xerrors) } - def compileFiles(path: String, args: List[String] = Nil): Unit = { + def compileFiles(path: String, args: List[String] = Nil)(implicit defaultOptions: List[String]): Unit = { val dir = Directory(path) val fileNames = dir.files.toArray.map(_.toString).filter(_ endsWith ".scala") for (name <- fileNames) { @@ -43,7 +41,7 @@ class CompilerTest extends DottyTest { } } } -object CompilerText extends App { +object CompilerTest extends App { // val dotcDir = "/Users/odersky/workspace/dotty/src/dotty/" diff --git a/test/test/transform/LazyValsTest.scala b/test/test/transform/LazyValsTest.scala index 98853ad60078..30c093f70eb1 100644 --- a/test/test/transform/LazyValsTest.scala +++ b/test/test/transform/LazyValsTest.scala @@ -183,8 +183,9 @@ class LazyValsTest extends DottyTest { (tree, ctx) => val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class lang),String)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(null))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(a))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))" val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class lang),String)],Literal(Constant(null))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))" - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val treeS = tree.toString + println(treeS) Assert.assertTrue("volatile field lazy ref rewritten to class creation", treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField)) } @@ -196,7 +197,7 @@ class LazyValsTest extends DottyTest { (tree, ctx) => val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))" val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Int)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))" - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val treeS = tree.toString Assert.assertTrue("volatile field lazy ref rewritten to class creation", treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField)) @@ -209,7 +210,7 @@ class LazyValsTest extends DottyTest { (tree, ctx) => val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Long)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))" val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))" - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val treeS = tree.toString Assert.assertTrue("volatile field lazy ref rewritten to class creation", treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField)) @@ -222,7 +223,7 @@ class LazyValsTest extends DottyTest { (tree, ctx) => val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Float)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1.0))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))" val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Float)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))" - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val treeS = tree.toString Assert.assertTrue("volatile field lazy ref rewritten to class creation", treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField)) @@ -235,7 +236,7 @@ class LazyValsTest extends DottyTest { (tree, ctx) => val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Double)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1.0))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))" val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Double)],Literal(Constant(0.0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))" - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val treeS = tree.toString Assert.assertTrue("volatile field lazy ref rewritten to class creation", treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField)) @@ -248,7 +249,7 @@ class LazyValsTest extends DottyTest { (tree, ctx) => val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Boolean)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(false))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(true))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))" val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(false))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))" - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val treeS = tree.toString Assert.assertTrue("volatile field lazy ref rewritten to class creation", treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField)) @@ -261,7 +262,7 @@ class LazyValsTest extends DottyTest { (tree, ctx) => val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),),List()))),s,List(),List(),TypeTree[TypeRef(TermRef(ThisType(module class ),scala),Byte)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))" val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(TermRef(ThisType(module class ),scala),Byte)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))" - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val treeS = tree.toString Assert.assertTrue("volatile field lazy ref rewritten to class creation", treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField)) @@ -274,7 +275,7 @@ class LazyValsTest extends DottyTest { (tree, ctx) => val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),),List()))),s,List(),List(),TypeTree[TypeRef(TermRef(ThisType(module class ),scala),Short)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(0))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(1))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))" val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(TermRef(ThisType(module class ),scala),Short)],Literal(Constant(0))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))" - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val treeS = tree.toString Assert.assertTrue("volatile field lazy ref rewritten to class creation", treeS.contains(accessor) && treeS.contains(fields) && treeS.contains(moduleField)) @@ -287,7 +288,7 @@ class LazyValsTest extends DottyTest { (tree, ctx) => val accessor = "DefDef(Modifiers(,,List(Apply(Select(New(Ident(volatile)),),List()))),s,List(),List(),TypeTree[TypeRef(ThisType(module class scala),Char)],Block(List(ValDef(Modifiers(,,List()),result,TypeTree[TermRef(ThisType(class LV),s)],Literal(Constant(\u0000))), ValDef(Modifiers(,,List()),retry,TypeTree[TypeRef(ThisType(module class scala),Boolean)],Literal(Constant(true))), ValDef(Modifiers(,,List()),flag,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0))), WhileDo(Ident(retry),Block(List(Assign(Ident(flag),Apply(Select(Ident(LazyVals),get),List(This(LV), Select(Ident(LV),OFFSET$0))))),Match(Apply(Select(Ident(LazyVals),STATE),List(Ident(flag), Literal(Constant(0)))),List(CaseDef(Literal(Constant(0)),EmptyTree,If(Apply(Select(Ident(LazyVals),CAS),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(1)), Literal(Constant(0)))),Block(List(Try(Assign(Ident(result),Literal(Constant(a))),Block(List(DefDef(Modifiers(,,List()),$anonfun,List(),List(List(ValDef(Modifiers(,,List()),x$1,TypeTree[TypeRef(ThisType(module class lang),Throwable)],EmptyTree))),TypeTree[TypeRef(ThisType(module class scala),Int)],Block(List(Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(0)), Literal(Constant(0))))),Throw(Ident(x$1))))),Closure(List(),Ident($anonfun),EmptyTree)),EmptyTree), Assign(Ident(s$lzy1),Ident(result)), Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(0)))), Assign(Ident(retry),Literal(Constant(false)))),Literal(Constant(()))),Literal(Constant(())))), CaseDef(Literal(Constant(1)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(2)),EmptyTree,Apply(Select(Ident(LazyVals),wait4Notification),List(This(LV), Select(Ident(LV),OFFSET$0), Ident(flag), Literal(Constant(0))))), CaseDef(Literal(Constant(3)),EmptyTree,Block(List(Assign(Ident(retry),Literal(Constant(false))), Assign(Ident(result),Ident(s$lzy1))),Literal(Constant(()))))))))),Ident(result)))" val fields = "ValDef(Modifiers(,,List()),s$lzy1,TypeTree[TypeRef(ThisType(module class scala),Char)],Literal(Constant(\u0000))), ValDef(Modifiers(,,List()),bitmap$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Literal(Constant(0)))" - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val treeS = tree.toString Assert.assertTrue("volatile field lazy ref rewritten to class creation", @@ -299,7 +300,7 @@ class LazyValsTest extends DottyTest { def volatilesReuseBitmaps = { checkCompile("LazyVals", "class LV { @volatile lazy val a = 'a'; @volatile lazy val b = 'b'; }") { (tree, ctx) => - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val reuseFieldPattern = "Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$0), Literal(Constant(3)), Literal(Constant(1))))" val treeS = tree.toString Assert.assertTrue("volatile field lazy ref rewritten to class creation", @@ -349,7 +350,7 @@ class LazyValsTest extends DottyTest { | } """.stripMargin ){ (tree, ctx) => - val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(TypeTree[TypeRef(ThisType(module class lang),Object)]),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$1,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$1))))), ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" + val moduleField = "TypeDef(Modifiers(final module ,,List()),LV$,Template(DefDef(Modifiers(,,List()),,List(),List(List()),TypeTree[TypeRef(ThisType(module class ),LV$)],EmptyTree),List(Apply(Select(New(TypeTree[TypeRef(ThisType(module class lang),Object)]),),List())),ValDef(Modifiers(,,List()),_,TypeTree[TermRef(ThisType(module class ),LV)],EmptyTree),List(ValDef(Modifiers(,,List()),OFFSET$1,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$1))))), ValDef(Modifiers(,,List()),OFFSET$0,TypeTree[TypeRef(ThisType(module class scala),Long)],Apply(Select(Ident(LazyVals),getOffset),List(This(LV), Literal(Constant(bitmap$0))))))))" val reuseFieldPattern = "Apply(Select(Ident(LazyVals),setFlag),List(This(LV), Select(Ident(LV),OFFSET$1), Literal(Constant(3)), Literal(Constant(1))))" val treeS = tree.toString Assert.assertTrue("volatile field lazy ref rewritten to class creation", diff --git a/tests/neg/tailcall/tailrec-2.scala b/tests/neg/tailcall/tailrec-2.scala index d6b8b1355b01..bc594293d7f6 100644 --- a/tests/neg/tailcall/tailrec-2.scala +++ b/tests/neg/tailcall/tailrec-2.scala @@ -13,7 +13,7 @@ class Bop2[+A](val element: A) extends Super[A] { @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = (null: Bop2[A]).f(mem) } object Bop3 extends Super[Nothing] { - @annotation.tailrec final def f[B](mem: List[B]): List[B] = (null: Bop3.type).f(mem) + @annotation.tailrec final def f[B](mem: List[B]): List[B] = (???: Bop3.type).f(mem) } class Bop4[+A](val element: A) extends Super[A] { @annotation.tailrec final def f[B >: A](mem: List[B]): List[B] = Other.f[A].f(mem) diff --git a/tests/pos/t1164.scala b/tests/pending/pos/t1164.scala similarity index 100% rename from tests/pos/t1164.scala rename to tests/pending/pos/t1164.scala