diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index b915373da021..0775b3caaf0c 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -480,7 +480,7 @@ object Flags { */ val AfterLoadFlags: FlagSet = commonFlags( FromStartFlags, AccessFlags, Final, AccessorOrSealed, - Abstract, LazyOrTrait, SelfName, JavaDefined, JavaAnnotation, Transparent, Tracked) + Abstract, LazyOrTrait, SelfName, JavaDefined, JavaAnnotation, Transparent) /** A value that's unstable unless complemented with a Stable flag */ val UnstableValueFlags: FlagSet = Mutable | Method diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 0849e57b8c7d..9ff01fb1a20e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -2016,6 +2016,11 @@ class Namer { typer: Typer => paramFn: Type => Type, fallbackProto: Type )(using Context): Type = + /** Is this member tracked? This is true if it is marked as `tracked` or if + * it overrides a `tracked` member. To account for the later, `isTracked` + * is overriden to `true` as a side-effect of computing `inherited`. + */ + var isTracked: Boolean = sym.is(Tracked) /** A type for this definition that might be inherited from elsewhere: * If this is a setter parameter, the corresponding getter type. @@ -2051,8 +2056,10 @@ class Namer { typer: Typer => if paramss.isEmpty then info.widenExpr else NoType - val iRawInfo = - cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema, sym.targetName).info + val iDenot = cls.info.nonPrivateDecl(sym.name).matchingDenotation(site, schema, sym.targetName) + val iSym = iDenot.symbol + if iSym.is(Tracked) then isTracked = true + val iRawInfo = iDenot.info val iResType = instantiatedResType(iRawInfo, paramss).asSeenFrom(site, cls) if (iResType.exists) typr.println(i"using inherited type for ${mdef.name}; raw: $iRawInfo, inherited: $iResType") @@ -2141,6 +2148,7 @@ class Namer { typer: Typer => if defaultTp.exists then TypeOps.SimplifyKeepUnchecked() else null) match case ctp: ConstantType if sym.isInlineVal => ctp + case tp if isTracked => tp case tp => TypeComparer.widenInferred(tp, pt, Widen.Unions) // Replace aliases to Unit by Unit itself. If we leave the alias in @@ -2151,7 +2159,7 @@ class Namer { typer: Typer => def lhsType = fullyDefinedType(cookedRhsType, "right-hand side", mdef.srcPos) //if (sym.name.toString == "y") println(i"rhs = $rhsType, cooked = $cookedRhsType") if (inherited.exists) - if sym.isInlineVal then lhsType else inherited + if sym.isInlineVal || isTracked then lhsType else inherited else { if (sym.is(Implicit)) mdef match { diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index ca1a2a98c55d..7ef6040daf90 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -2834,20 +2834,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer case rhs => excludeDeferredGiven(rhs, sym): typedExpr(_, tpt1.tpe.widenExpr) - setAbstractTrackedInfo(sym, rhs1, tpt) - val tpt2 = if sym.flags.is(Tracked) && tpt.isEmpty && !sym.flags.is(ParamAccessor) && !sym.flags.is(Param) then TypeTree(rhs1.tpe) else tpt1 - val vdef2 = assignType(cpy.ValDef(vdef)(name, tpt2, rhs1), sym) - postProcessInfo(vdef2, sym) - vdef2.setDefTree + val vdef1 = assignType(cpy.ValDef(vdef)(name, tpt1, rhs1), sym) + postProcessInfo(vdef1, sym) + vdef1.setDefTree } - - private def setAbstractTrackedInfo(sym: Symbol, rhs: Tree, tpt: untpd.Tree)(using Context): Unit = - if !sym.flags.is(ParamAccessor) && !sym.flags.is(Param) then - if sym.allOverriddenSymbols.exists(_.flags.is(Tracked)) then - sym.setFlag(Tracked) - if sym.flags.is(Tracked) && tpt.isEmpty then - sym.info = rhs.tpe - private def retractDefDef(sym: Symbol)(using Context): Tree = // it's a discarded method (synthetic case class method or synthetic java record constructor or overridden member), drop it val canBeInvalidated: Boolean = diff --git a/tests/pos/abstract-tracked-2.scala b/tests/pos/abstract-tracked-2.scala new file mode 100644 index 000000000000..01e4ee84c548 --- /dev/null +++ b/tests/pos/abstract-tracked-2.scala @@ -0,0 +1,11 @@ +import scala.language.experimental.modularity +import scala.language.future + +abstract class Vec: + tracked val size: Int + +@main def main = + val v = new Vec: + val size0: size.type = 10 + val size = 10 + val size1: size.type = 10