diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 8401d255155c..98eb8f895f5b 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -2263,9 +2263,9 @@ object desugar { AppliedTypeTree(ref(defn.SeqType), t), New(ref(defn.RepeatedAnnot.typeRef), Nil :: Nil)) else if op.name == nme.CC_REACH then - Apply(ref(defn.Caps_reachCapability), t :: Nil) + Annotated(t, New(ref(defn.ReachCapabilityAnnot.typeRef), Nil :: Nil)) else if op.name == nme.CC_READONLY then - Apply(ref(defn.Caps_readOnlyCapability), t :: Nil) + Annotated(t, New(ref(defn.ReadOnlyCapabilityAnnot.typeRef), Nil :: Nil)) else assert(ctx.mode.isExpr || ctx.reporter.errorsReported || ctx.mode.is(Mode.Interactive), ctx.mode) Select(t, op.name) diff --git a/compiler/src/dotty/tools/dotc/ast/untpd.scala b/compiler/src/dotty/tools/dotc/ast/untpd.scala index e9a6e148ce86..63639dcb3c15 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -388,6 +388,8 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { /** Property key for contextual Apply trees of the form `fn given arg` */ val KindOfApply: Property.StickyKey[ApplyKind] = Property.StickyKey() + val RetainsAnnot: Property.StickyKey[Unit] = Property.StickyKey() + // ------ Creation methods for untyped only ----------------- def Ident(name: Name)(implicit src: SourceFile): Ident = new Ident(name) @@ -530,10 +532,23 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { Select(scalaDot(nme.caps), nme.CAPTURE_ROOT) def makeRetaining(parent: Tree, refs: List[Tree], annotName: TypeName)(using Context): Annotated = - Annotated(parent, New(scalaAnnotationDot(annotName), List(refs))) - - def makeCapsOf(tp: RefTree)(using Context): Tree = - TypeApply(capsInternalDot(nme.capsOf), tp :: Nil) + var annot: Tree = scalaAnnotationDot(annotName) + if annotName == tpnme.retainsCap then + annot = New(annot, Nil) + else + val trefs = + if refs.isEmpty then + // The NothingType is used to represent the empty capture set. + ref(defn.NothingType) + else + // Treat all references as term references before typing. + // A dummy term symbol will be created for each capture variable, + // and references to them will be replaced with the corresponding + // type references during typing. + refs.map(SingletonTypeTree).reduce[Tree]((a, b) => makeOrType(a, b)) + annot = New(AppliedTypeTree(annot, trefs :: Nil), Nil) + annot.putAttachment(RetainsAnnot, ()) + Annotated(parent, annot) def makeConstructor(tparams: List[TypeDef], vparamss: List[List[ValDef]], rhs: Tree = EmptyTree)(using Context): DefDef = DefDef(nme.CONSTRUCTOR, joinParams(tparams, vparamss), TypeTree(), rhs) @@ -557,6 +572,9 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo { def makeAndType(left: Tree, right: Tree)(using Context): AppliedTypeTree = AppliedTypeTree(ref(defn.andType.typeRef), left :: right :: Nil) + def makeOrType(left: Tree, right: Tree)(using Context): AppliedTypeTree = + AppliedTypeTree(ref(defn.orType.typeRef), left :: right :: Nil) + def makeParameter(pname: TermName, tpe: Tree, mods: Modifiers, isBackquoted: Boolean = false)(using Context): ValDef = { val vdef = ValDef(pname, tpe, EmptyTree) if (isBackquoted) vdef.pushAttachment(Backquoted, ()) diff --git a/compiler/src/dotty/tools/dotc/cc/Capability.scala b/compiler/src/dotty/tools/dotc/cc/Capability.scala index 95f8f180b339..7ad77b9914d8 100644 --- a/compiler/src/dotty/tools/dotc/cc/Capability.scala +++ b/compiler/src/dotty/tools/dotc/cc/Capability.scala @@ -603,6 +603,17 @@ object Capabilities: def assumedContainsOf(x: TypeRef)(using Context): SimpleIdentitySet[Capability] = CaptureSet.assumedContains.getOrElse(x, SimpleIdentitySet.empty) + def toType(using Context): Type = this match + case c: RootCapability => defn.captureRoot.termRef + case c: CoreCapability => c + case c: DerivedCapability => + val c1 = c.underlying.toType + c match + case _: ReadOnly => ReadOnlyCapability(c1) + case _: Reach => ReachCapability(c1) + case _: Maybe => MaybeCapability(c1) + case _ => c1 + def toText(printer: Printer): Text = printer.toTextCapability(this) end Capability diff --git a/compiler/src/dotty/tools/dotc/cc/CaptureAnnotation.scala b/compiler/src/dotty/tools/dotc/cc/CaptureAnnotation.scala index 2af01594192f..60183126bca2 100644 --- a/compiler/src/dotty/tools/dotc/cc/CaptureAnnotation.scala +++ b/compiler/src/dotty/tools/dotc/cc/CaptureAnnotation.scala @@ -39,15 +39,14 @@ case class CaptureAnnotation(refs: CaptureSet, boxed: Boolean)(cls: Symbol) exte /** Reconstitute annotation tree from capture set */ override def tree(using Context) = - val elems = refs.elems.toList.map { - case c: TermRef => ref(c) - case c: TermParamRef => untpd.Ident(c.paramName).withType(c) - case c: ThisType => This(c.cls) - case c: RootCapability => ref(defn.captureRoot) - // TODO: Will crash if the type is an annotated type, for example `cap.rd` - } - val arg = repeated(elems, TypeTree(defn.AnyType)) - New(symbol.typeRef, arg :: Nil) + if symbol == defn.RetainsCapAnnot then + New(symbol.typeRef, Nil) + else + val elems = refs.elems.toList.map(_.toType) + val trefs = + if elems.isEmpty then defn.NothingType + else elems.reduce((a, b) => OrType(a, b, soft = false)) + New(AppliedType(symbol.typeRef, trefs :: Nil), Nil) override def symbol(using Context) = cls diff --git a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala index 3dd847f19b56..786cd0b02878 100644 --- a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala +++ b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala @@ -47,28 +47,6 @@ def ccState(using Context): CCState = extension (tree: Tree) - /** Map tree with a Capability type to the corresponding capability, - * map CapSet^{refs} to the `refs` references, - * throw IllegalCaptureRef otherwise - */ - def toCapabilities(using Context): List[Capability] = tree match - case ReachCapabilityApply(arg) => - arg.toCapabilities.map(_.reach) - case ReadOnlyCapabilityApply(arg) => - arg.toCapabilities.map(_.readOnly) - case CapsOfApply(arg) => - arg.toCapabilities - case _ => tree.tpe.dealiasKeepAnnots match - case ref: TermRef if ref.isCapRef => - GlobalCap :: Nil - case ref: Capability if ref.isTrackableRef => - ref :: Nil - case AnnotatedType(parent, ann) - if ann.symbol.isRetains && parent.derivesFrom(defn.Caps_CapSet) => - ann.tree.toCaptureSet.elems.toList - case tpe => - throw IllegalCaptureRef(tpe) // if this was compiled from cc syntax, problem should have been reported at Typer - /** Convert a @retains or @retainsByName annotation tree to the capture set it represents. * For efficience, the result is cached as an Attachment on the tree. */ @@ -76,28 +54,52 @@ extension (tree: Tree) tree.getAttachment(Captures) match case Some(refs) => refs case None => - val refs = CaptureSet(tree.retainedElems.flatMap(_.toCapabilities)*) - //.showing(i"toCaptureSet $tree --> $result", capt) + val refs = CaptureSet(tree.retainedSet.retainedElements*) tree.putAttachment(Captures, refs) refs - /** The arguments of a @retains, @retainsCap or @retainsByName annotation */ - def retainedElems(using Context): List[Tree] = tree match - case Apply(_, Typed(SeqLiteral(elems, _), _) :: Nil) => - elems - case _ => - if tree.symbol.maybeOwner == defn.RetainsCapAnnot - then ref(defn.captureRoot) :: Nil - else Nil + /** The type representing the capture set of @retains, @retainsCap or @retainsByName annotation. */ + def retainedSet(using Context): Type = + tree match + case Apply(TypeApply(_, refs :: Nil), _) => refs.tpe + case _ => + if tree.symbol.maybeOwner == defn.RetainsCapAnnot + then defn.captureRoot.termRef else NoType extension (tp: Type) + def toCapability(using Context): Capability = tp match + case ReachCapability(tp1) => + tp1.toCapability.reach + case ReadOnlyCapability(tp1) => + tp1.toCapability.readOnly + case ref: TermRef if ref.isCapRef => + GlobalCap + case ref: Capability if ref.isTrackableRef => + ref + case _ => + // if this was compiled from cc syntax, problem should have been reported at Typer + throw IllegalCaptureRef(tp) + + /** A list of raw elements of a retained set. + * This will not crash even if it contains a non-wellformed Capability. + */ + def retainedElementsRaw(using Context): List[Type] = tp match + case OrType(tp1, tp2) => + tp1.retainedElementsRaw ++ tp2.retainedElementsRaw + case tp => + // Nothing is a special type to represent the empty set + if tp.isNothingType then Nil + else tp :: Nil // should be checked by wellformedness + + /** A list of capabilities of a retained set. */ + def retainedElements(using Context): List[Capability] = + retainedElementsRaw.map(_.toCapability) + /** Is this type a Capability that can be tracked? * This is true for * - all ThisTypes and all TermParamRef, * - stable TermRefs with NoPrefix or ThisTypes as prefixes, - * - the root capability `caps.cap` - * - abstract or parameter TypeRefs that derive from caps.CapSet * - annotated types that represent reach or maybe capabilities */ final def isTrackableRef(using Context): Boolean = tp match @@ -408,7 +410,7 @@ extension (cls: ClassSymbol) || bc.is(CaptureChecked) && bc.givenSelfType.dealiasKeepAnnots.match case CapturingType(_, refs) => refs.isAlwaysEmpty - case RetainingType(_, refs) => refs.isEmpty + case RetainingType(_, refs) => refs.retainedElements.isEmpty case selfType => isCaptureChecking // At Setup we have not processed self types yet, so // unless a self type is explicitly given, we can't tell @@ -523,32 +525,36 @@ class CleanupRetains(using Context) extends TypeMap: def apply(tp: Type): Type = tp match case AnnotatedType(tp, annot) if annot.symbol == defn.RetainsAnnot || annot.symbol == defn.RetainsByNameAnnot => - RetainingType(tp, Nil, byName = annot.symbol == defn.RetainsByNameAnnot) + RetainingType(tp, defn.NothingType, byName = annot.symbol == defn.RetainsByNameAnnot) case _ => mapOver(tp) -/** An extractor for `caps.reachCapability(ref)`, which is used to express a reach - * capability as a tree in a @retains annotation. +/** A base class for extractors that match annotated types with a specific + * Capability annotation. */ -object ReachCapabilityApply: - def unapply(tree: Apply)(using Context): Option[Tree] = tree match - case Apply(reach, arg :: Nil) if reach.symbol == defn.Caps_reachCapability => Some(arg) +abstract class AnnotatedCapability(annotCls: Context ?=> ClassSymbol): + def apply(tp: Type)(using Context): AnnotatedType = + AnnotatedType(tp, Annotation(annotCls, util.Spans.NoSpan)) + + def unapply(tree: AnnotatedType)(using Context): Option[Type] = tree match + case AnnotatedType(parent: Type, ann) if ann.hasSymbol(annotCls) => Some(parent) case _ => None -/** An extractor for `caps.readOnlyCapability(ref)`, which is used to express a read-only - * capability as a tree in a @retains annotation. +end AnnotatedCapability + +/** An extractor for `ref @readOnlyCapability`, which is used to express + * the read-only capability `ref.rd` as a type. */ -object ReadOnlyCapabilityApply: - def unapply(tree: Apply)(using Context): Option[Tree] = tree match - case Apply(ro, arg :: Nil) if ro.symbol == defn.Caps_readOnlyCapability => Some(arg) - case _ => None +object ReadOnlyCapability extends AnnotatedCapability(defn.ReadOnlyCapabilityAnnot) -/** An extractor for `caps.capsOf[X]`, which is used to express a generic capture set - * as a tree in a @retains annotation. +/** An extractor for `ref @reachCapability`, which is used to express + * the reach capability `ref*` as a type. */ -object CapsOfApply: - def unapply(tree: TypeApply)(using Context): Option[Tree] = tree match - case TypeApply(capsOf, arg :: Nil) if capsOf.symbol == defn.Caps_capsOf => Some(arg) - case _ => None +object ReachCapability extends AnnotatedCapability(defn.ReachCapabilityAnnot) + +/** An extractor for `ref @amaybeCapability`, which is used to express + * the maybe capability `ref?` as a type. + */ +object MaybeCapability extends AnnotatedCapability(defn.MaybeCapabilityAnnot) /** An extractor for all kinds of function types as well as method and poly types. * It includes aliases of function types such as `=>`. TODO: Can we do without? diff --git a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala index 1bdd7ce92129..f3b9b2e8e932 100644 --- a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala +++ b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala @@ -100,25 +100,24 @@ object CheckCaptures: * This check is performed at Typer. */ def checkWellformed(parent: Tree, ann: Tree)(using Context): Unit = - def check(elem: Tree, pos: SrcPos): Unit = elem.tpe match + def check(elem: Type, pos: SrcPos): Unit = elem match case ref: Capability => if !ref.isTrackableRef && !ref.isCapRef then report.error(em"$elem cannot be tracked since it is not a parameter or local value", pos) case tpe => report.error(em"$elem: $tpe is not a legal element of a capture set", pos) - for elem <- ann.retainedElems do + for elem <- ann.retainedSet.retainedElementsRaw do elem match - case CapsOfApply(arg) => - def isLegalCapsOfArg = - arg.symbol.isType && arg.symbol.info.derivesFrom(defn.Caps_CapSet) - if !isLegalCapsOfArg then - report.error( - em"""$arg is not a legal prefix for `^` here, - |is must be a type parameter or abstract type with a caps.CapSet upper bound.""", - elem.srcPos) - case ReachCapabilityApply(arg) => check(arg, elem.srcPos) - case ReadOnlyCapabilityApply(arg) => check(arg, elem.srcPos) - case _ => check(elem, elem.srcPos) + case ref: TypeRef => + val refSym = ref.symbol + if refSym.isType && !refSym.info.derivesFrom(defn.Caps_CapSet) then + report.error(em"$elem is not a legal element of a capture set", ann.srcPos) + case ReachCapability(ref) => + check(ref, ann.srcPos) + case ReadOnlyCapability(ref) => + check(ref, ann.srcPos) + case _ => + check(elem, ann.srcPos) /** Under the sealed policy, report an error if some part of `tp` contains the * root capability in its capture set or if it refers to a type parameter that diff --git a/compiler/src/dotty/tools/dotc/cc/RetainingType.scala b/compiler/src/dotty/tools/dotc/cc/RetainingType.scala index efd0e96fd658..8bdd6a7301a8 100644 --- a/compiler/src/dotty/tools/dotc/cc/RetainingType.scala +++ b/compiler/src/dotty/tools/dotc/cc/RetainingType.scala @@ -12,16 +12,12 @@ import Decorators.i */ object RetainingType: - def apply(tp: Type, refs: List[Tree], byName: Boolean = false)(using Context): Type = + def apply(tp: Type, typeElems: Type, byName: Boolean = false)(using Context): Type = val annotCls = if byName then defn.RetainsByNameAnnot else defn.RetainsAnnot - val annotTree = - New(annotCls.typeRef, - Typed( - SeqLiteral(refs, TypeTree(defn.AnyType)), - TypeTree(defn.RepeatedParamClass.typeRef.appliedTo(defn.AnyType))) :: Nil) + val annotTree = New(AppliedType(annotCls.typeRef, typeElems :: Nil), Nil) AnnotatedType(tp, Annotation(annotTree)) - def unapply(tp: AnnotatedType)(using Context): Option[(Type, List[Tree])] = + def unapply(tp: AnnotatedType)(using Context): Option[(Type, Type)] = val sym = tp.annot.symbol if sym.isRetainsLike then tp.annot match @@ -29,7 +25,7 @@ object RetainingType: assert(ctx.mode.is(Mode.IgnoreCaptures), s"bad retains $tp at ${ctx.phase}") None case ann => - Some((tp.parent, ann.tree.retainedElems)) + Some((tp.parent, ann.tree.retainedSet)) else None end RetainingType diff --git a/compiler/src/dotty/tools/dotc/cc/Setup.scala b/compiler/src/dotty/tools/dotc/cc/Setup.scala index 69bfa96df836..1357df42915e 100644 --- a/compiler/src/dotty/tools/dotc/cc/Setup.scala +++ b/compiler/src/dotty/tools/dotc/cc/Setup.scala @@ -806,7 +806,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI: case CapturingType(_, refs) => !refs.isAlwaysEmpty case RetainingType(parent, refs) => - !refs.isEmpty + !refs.retainedElements.isEmpty case tp: (TypeRef | AppliedType) => val sym = tp.typeSymbol if sym.isClass @@ -852,7 +852,7 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI: && !refs.isUniversal // if refs is {cap}, an added variable would not change anything case RetainingType(parent, refs) => needsVariable(parent) - && !refs.tpes.exists: + && !refs.retainedElements.exists: case ref: TermRef => ref.isCapRef case _ => false case AnnotatedType(parent, _) => @@ -947,19 +947,13 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI: * @param tpt the tree for which an error or warning should be reported */ private def checkWellformed(parent: Type, ann: Tree, tpt: Tree)(using Context): Unit = - capt.println(i"checkWF post $parent ${ann.retainedElems} in $tpt") - var retained = ann.retainedElems.toArray - for i <- 0 until retained.length do - val refTree = retained(i) - val refs = - try refTree.toCapabilities - catch case ex: IllegalCaptureRef => - report.error(em"Illegal capture reference: ${ex.getMessage}", refTree.srcPos) - Nil - for ref <- refs do + capt.println(i"checkWF post $parent ${ann.retainedSet} in $tpt") + try + var retained = ann.retainedSet.retainedElements.toArray + for i <- 0 until retained.length do + val ref = retained(i) def pos = - if refTree.span.exists then refTree.srcPos - else if ann.span.exists then ann.srcPos + if ann.span.exists then ann.srcPos else tpt.srcPos def check(others: CaptureSet, dom: Type | CaptureSet): Unit = @@ -976,13 +970,14 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI: val others = for j <- 0 until retained.length if j != i - r <- retained(j).toCapabilities + r = retained(j) if !r.isTerminalCapability yield r val remaining = CaptureSet(others*) check(remaining, remaining) end for - end for + catch case ex: IllegalCaptureRef => + report.error(em"Illegal capture reference: ${ex.getMessage}", tpt.srcPos) end checkWellformed /** Check well formed at post check time. We need to wait until after diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 83c85adb0f43..40483eaf4443 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -123,7 +123,7 @@ class Definitions { HKTypeLambda(argParamNames :+ "R".toTypeName, argVariances :+ Covariant)( tl => List.fill(arity + 1)(TypeBounds.empty), tl => RetainingType(underlyingClass.typeRef.appliedTo(tl.paramRefs), - ref(captureRoot.termRef) :: Nil) + captureRoot.termRef) )) else val cls = denot.asClass.classSymbol @@ -1004,9 +1004,6 @@ class Definitions { @tu lazy val Caps_Capability: ClassSymbol = requiredClass("scala.caps.Capability") @tu lazy val Caps_CapSet: ClassSymbol = requiredClass("scala.caps.CapSet") @tu lazy val CapsInternalModule: Symbol = requiredModule("scala.caps.internal") - @tu lazy val Caps_reachCapability: TermSymbol = CapsInternalModule.requiredMethod("reachCapability") - @tu lazy val Caps_readOnlyCapability: TermSymbol = CapsInternalModule.requiredMethod("readOnlyCapability") - @tu lazy val Caps_capsOf: TermSymbol = CapsInternalModule.requiredMethod("capsOf") @tu lazy val CapsUnsafeModule: Symbol = requiredModule("scala.caps.unsafe") @tu lazy val Caps_unsafeAssumePure: Symbol = CapsUnsafeModule.requiredMethod("unsafeAssumePure") @tu lazy val Caps_unsafeAssumeSeparate: Symbol = CapsUnsafeModule.requiredMethod("unsafeAssumeSeparate") @@ -1096,7 +1093,6 @@ class Definitions { @tu lazy val RetainsAnnot: ClassSymbol = requiredClass("scala.annotation.retains") @tu lazy val RetainsCapAnnot: ClassSymbol = requiredClass("scala.annotation.retainsCap") @tu lazy val RetainsByNameAnnot: ClassSymbol = requiredClass("scala.annotation.retainsByName") - @tu lazy val RetainsArgAnnot: ClassSymbol = requiredClass("scala.annotation.retainsArg") @tu lazy val PublicInBinaryAnnot: ClassSymbol = requiredClass("scala.annotation.publicInBinary") @tu lazy val WitnessNamesAnnot: ClassSymbol = requiredClass("scala.annotation.internal.WitnessNames") @@ -1332,8 +1328,8 @@ class Definitions { */ object ByNameFunction: def apply(tp: Type)(using Context): Type = tp match - case tp @ RetainingType(tp1, refs) if tp.annot.symbol == RetainsByNameAnnot => - RetainingType(apply(tp1), refs) + case tp @ RetainingType(tp1, refSet) if tp.annot.symbol == RetainsByNameAnnot => + RetainingType(apply(tp1), refSet) case _ => defn.ContextFunction0.typeRef.appliedTo(tp :: Nil) def unapply(tp: Type)(using Context): Option[Type] = tp match @@ -1562,11 +1558,6 @@ class Definitions { @tu lazy val pureSimpleClasses = Set(StringClass, NothingClass, NullClass) ++ ScalaValueClasses() - @tu lazy val capabilityQualifierAnnots: Set[Symbol] = - Set(ReachCapabilityAnnot, ReadOnlyCapabilityAnnot, MaybeCapabilityAnnot) - @tu lazy val capabilityWrapperAnnots: Set[Symbol] = - capabilityQualifierAnnots + RootCapabilityAnnot - @tu lazy val AbstractFunctionType: Array[TypeRef] = mkArityArray("scala.runtime.AbstractFunction", MaxImplementedFunctionArity, 0).asInstanceOf[Array[TypeRef]] val AbstractFunctionClassPerRun: PerRun[Array[Symbol]] = new PerRun(AbstractFunctionType.map(_.symbol.asClass)) def AbstractFunctionClass(n: Int)(using Context): Symbol = AbstractFunctionClassPerRun()(using ctx)(n) diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 6adf899e9da0..c040d3e206b9 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -433,8 +433,12 @@ object Flags { /** A denotation that is valid in all run-ids */ val (Permanent @ _, _, _) = newFlags(61, "") - /** Symbol is a constructor proxy (either companion, or apply method) */ - val (ConstructorProxy @ _, _, _) = newFlags(62, "") // (could be merged with Lifted) + /** A phantom symbol made up by the compiler to achieve special typing rules. + * Phantom symbols cannot be used as regular values, and will be erased after erasure phase. + * - For constructor proxies (companion or apply method). + * - For dummy capture parameters in capture sets (variables or fields). + */ + val (PhantomSymbol @ _, _, _) = newFlags(62, "") // (could be merged with Lifted) // --------- Combined Flag Sets and Conjunctions ---------------------- @@ -471,7 +475,7 @@ object Flags { Scala2SpecialFlags, MutableOrOpen, Opaque, Touched, JavaStatic, OuterOrCovariant, LabelOrContravariant, CaseAccessor, Tracked, Extension, NonMember, Implicit, Given, Permanent, Synthetic, Exported, - SuperParamAliasOrScala2x, Inline, Macro, ConstructorProxy, Invisible) + SuperParamAliasOrScala2x, Inline, Macro, PhantomSymbol, Invisible) /** Flags that are not (re)set when completing the denotation, or, if symbol is * a top-level class or object, when completing the denotation once the class @@ -525,7 +529,7 @@ object Flags { val RetainedModuleValAndClassFlags: FlagSet = AccessFlags | Package | Case | Synthetic | JavaDefined | JavaStatic | Artifact | - Lifted | MixedIn | Specialized | ConstructorProxy | Invisible | Erased + Lifted | MixedIn | Specialized | PhantomSymbol | Invisible | Erased /** Flags that can apply to a module val */ val RetainedModuleValFlags: FlagSet = RetainedModuleValAndClassFlags | @@ -565,8 +569,9 @@ object Flags { val EnumCase: FlagSet = Case | Enum val CovariantLocal: FlagSet = Covariant | Local // A covariant type parameter val ContravariantLocal: FlagSet = Contravariant | Local // A contravariant type parameter - val EffectivelyErased = ConstructorProxy | Erased - val ConstructorProxyModule: FlagSet = ConstructorProxy | Module + val EffectivelyErased = PhantomSymbol | Erased + val ConstructorProxyModule: FlagSet = PhantomSymbol | Module + val CaptureParam: FlagSet = PhantomSymbol | StableRealizable | Synthetic val DefaultParameter: FlagSet = HasDefault | Param // A Scala 2x default parameter val DeferredInline: FlagSet = Deferred | Inline val DeferredMethod: FlagSet = Deferred | Method @@ -579,7 +584,7 @@ object Flags { val FinalOrInline: FlagSet = Final | Inline val FinalOrModuleClass: FlagSet = Final | ModuleClass // A module class or a final class val EffectivelyFinalFlags: FlagSet = Final | Private - val ExcludedForwarder: Flags.FlagSet = Specialized | Lifted | Protected | JavaStatic | Private | Macro | ConstructorProxy + val ExcludedForwarder: Flags.FlagSet = Specialized | Lifted | Protected | JavaStatic | Private | Macro | PhantomSymbol val FinalOrSealed: FlagSet = Final | Sealed val GivenOrImplicit: FlagSet = Given | Implicit val GivenOrImplicitVal: FlagSet = GivenOrImplicit.toTermFlags diff --git a/compiler/src/dotty/tools/dotc/core/NamerOps.scala b/compiler/src/dotty/tools/dotc/core/NamerOps.scala index 6efb75ebac93..a5638c3f8a72 100644 --- a/compiler/src/dotty/tools/dotc/core/NamerOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NamerOps.scala @@ -114,10 +114,10 @@ object NamerOps: private val NoConstructorProxyNeededFlags = Abstract | Trait | Case | Synthetic | Module | Invisible /** The flags of a constructor companion */ - private val ConstructorCompanionFlags = Synthetic | ConstructorProxy + private val ConstructorCompanionFlags = Synthetic | PhantomSymbol /** The flags of an `apply` method that serves as a constructor proxy */ - val ApplyProxyFlags = Synthetic | ConstructorProxy | Inline | Method + val ApplyProxyFlags = Synthetic | PhantomSymbol | Inline | Method /** If this is a reference to a class and the reference has a stable prefix, the reference * otherwise NoType @@ -217,7 +217,7 @@ object NamerOps: underlyingStableClassRef(mbr.info.loBound): @unchecked match case ref: TypeRef => val proxy = ref.symbol.registeredCompanion - if proxy.is(ConstructorProxy) && !memberExists(cls, mbr.name.toTermName) then + if proxy.is(PhantomSymbol) && !memberExists(cls, mbr.name.toTermName) then typeConstructorCompanion(mbr, ref.prefix, proxy).entered if cls.is(Module) @@ -316,10 +316,24 @@ object NamerOps: case ast.tpd.WitnessNamesAnnot(witnessNames) => addContextBoundCompanionFor(sym, witnessNames, Nil) + /** Add a dummy term symbol for a type def that has capture parameter flag. + * The dummy symbol has the same name as the original type symbol and is stable. + * The underlying info stores the corresponding type reference. + * + * @param param the original type symbol of the capture parameter + */ + def addDummyTermCaptureParam(param: Symbol)(using Context): Unit = + val name = param.name.toTermName + val flags = (param.flagsUNSAFE & AccessFlags).toTermFlags | CaptureParam + val dummy = newSymbol(param.owner, name, flags, param.typeRef) + typr.println(i"Adding dummy term symbol $dummy for $param, flags = $flags") + ctx.enter(dummy) + /** if `sym` is a term parameter or parameter accessor, map all occurrences of * `into[T]` in its type to `T @$into`. */ extension (tp: Type) def suppressIntoIfParam(sym: Symbol)(using Context): Type = if sym.isOneOf(TermParamOrAccessor) then TypeOps.suppressInto(tp) else tp + end NamerOps diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index ac1f4f448722..d6afd8d4b872 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -444,7 +444,6 @@ object StdNames { val canEqual_ : N = "canEqual" val canEqualAny : N = "canEqualAny" val caps: N = "caps" - val capsOf: N = "capsOf" val captureChecking: N = "captureChecking" val checkInitialized: N = "checkInitialized" val classOf: N = "classOf" @@ -548,10 +547,10 @@ object StdNames { val ManifestFactory: N = "ManifestFactory" val manifestToTypeTag: N = "manifestToTypeTag" val map: N = "map" - val maybeCapability: N = "maybeCapability" val materializeClassTag: N = "materializeClassTag" val materializeWeakTypeTag: N = "materializeWeakTypeTag" val materializeTypeTag: N = "materializeTypeTag" + val maybeCapability: N = "maybeCapability" val mirror : N = "mirror" val moduleClass : N = "moduleClass" val mut: N = "mut" diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 53f991806641..2f04f390feb4 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -538,7 +538,7 @@ object SymDenotations { // doesn't find them it will invalidate whatever referenced them, so // any reference to a fake companion will lead to extra recompilations. // Instead, use the class name since it's guaranteed to exist at runtime. - val clsFlatName = if isOneOf(JavaDefined | ConstructorProxy) then flatName.stripModuleClassSuffix else flatName + val clsFlatName = if isOneOf(JavaDefined | PhantomSymbol) then flatName.stripModuleClassSuffix else flatName builder.append(clsFlatName.mangledString) builder.toString @@ -786,9 +786,14 @@ object SymDenotations { * * However, a stable member might not yet be initialized (if it is an object or anyhow lazy). * So the first call to a stable member might fail and/or produce side effects. + * + * Note, (f: => T) is treated as a stable TermRef only in Capture Sets. */ final def isStableMember(using Context): Boolean = { - def isUnstableValue = isOneOf(UnstableValueFlags) || info.isInstanceOf[ExprType] || isAllOf(InlineParam) + def isUnstableValue = + isOneOf(UnstableValueFlags) + || !ctx.mode.is(Mode.InCaptureSet) && info.isInstanceOf[ExprType] + || isAllOf(InlineParam) isType || is(StableRealizable) || exists && !isUnstableValue } diff --git a/compiler/src/dotty/tools/dotc/core/SymUtils.scala b/compiler/src/dotty/tools/dotc/core/SymUtils.scala index 3c59cecfbbff..34908a2df6d6 100644 --- a/compiler/src/dotty/tools/dotc/core/SymUtils.scala +++ b/compiler/src/dotty/tools/dotc/core/SymUtils.scala @@ -90,6 +90,9 @@ class SymUtils: def isContextBoundCompanion(using Context): Boolean = self.is(Synthetic) && self.infoOrCompleter.typeSymbol == defn.CBCompanion + def isDummyCaptureParam(using Context): Boolean = + self.isAllOf(CaptureParam) && !(self.isClass || self.is(Method)) + /** Is this a case class for which a product mirror is generated? * Excluded are value classes, abstract classes and case classes with more than one * parameter section. diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 0365b205c5b6..83f087239477 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -271,7 +271,7 @@ object TypeErasure { if (defn.isPolymorphicAfterErasure(sym)) eraseParamBounds(sym.info.asInstanceOf[PolyType]) else if (sym.isAbstractOrParamType) TypeAlias(WildcardType) - else if sym.is(ConstructorProxy) then NoType + else if sym.is(PhantomSymbol) then NoType else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(using preErasureCtx)) else if (sym.is(Label)) erase.eraseResult(sym.info)(using preErasureCtx) else erase.eraseInfo(tp, sym)(using preErasureCtx) match { diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 750e4b646e0d..6f4a40f41c93 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -174,21 +174,17 @@ class PlainPrinter(_ctx: Context) extends Printer { // ~ Str("?").provided(!cs.isConst) core ~ cs.optionalInfo - private def toTextRetainedElem[T <: Untyped](ref: Tree[T]): Text = ref match - case ref: RefTree[?] => - ref.typeOpt match - case c: Capability => toTextCapability(c) - case _ => toText(ref) - case TypeApply(fn, arg :: Nil) if fn.symbol == defn.Caps_capsOf => - toTextRetainedElem(arg) - case ReachCapabilityApply(ref1) => toTextRetainedElem(ref1) ~ "*" - case ReadOnlyCapabilityApply(ref1) => toTextRetainedElem(ref1) ~ ".rd" - case _ => toText(ref) - - private def toTextRetainedElems[T <: Untyped](refs: List[Tree[T]]): Text = + private def toTextRetainedElem(ref: Type): Text = ref match + case c: Capability => toTextCapability(c) + case _ => + try toTextCapability(ref.toCapability) + catch case _ => + toText(ref) + + private def toTextRetainedElems(refs: List[Type]): Text = "{" ~ Text(refs.map(ref => toTextRetainedElem(ref)), ", ") ~ "}" - type GeneralCaptureSet = CaptureSet | List[tpd.Tree] + type GeneralCaptureSet = CaptureSet | List[Type] protected def isUniversalCaptureSet(refs: GeneralCaptureSet): Boolean = refs match case refs: CaptureSet => @@ -207,12 +203,12 @@ class PlainPrinter(_ctx: Context) extends Printer { ) isUniversal || !refs.elems.isEmpty && refs.elems.forall(_.isCapOrFresh) && !ccVerbose - case (ref: tpd.Tree) :: Nil => ref.symbol == defn.captureRoot + case (ref: TermRef) :: Nil => ref.symbol == defn.captureRoot case _ => false protected def toTextGeneralCaptureSet(refs: GeneralCaptureSet): Text = refs match case refs: CaptureSet => toTextCaptureSet(refs) - case refs: List[tpd.Tree] => toTextRetainedElems(refs) + case refs: List[Type] => toTextRetainedElems(refs) /** Print capturing type, overridden in RefinedPrinter to account for * capturing function types. @@ -288,9 +284,9 @@ class PlainPrinter(_ctx: Context) extends Printer { && refs.isReadOnly then toText(parent) else toTextCapturing(parent, refs, boxText) - case tp @ RetainingType(parent, refs) => + case tp @ RetainingType(parent, refSet) => if Feature.ccEnabledSomewhere then - toTextCapturing(parent, refs, "") ~ Str("R").provided(printDebug) + toTextCapturing(parent, refSet.retainedElementsRaw, "") ~ Str("R").provided(printDebug) else toText(parent) case tp: PreviousErrorType if ctx.settings.XprintTypes.value => "" // do not print previously reported error message because they may try to print this error type again recursively @@ -315,8 +311,8 @@ class PlainPrinter(_ctx: Context) extends Printer { case ExprType(restp) => def arrowText: Text = restp match case AnnotatedType(parent, ann) if ann.symbol == defn.RetainsByNameAnnot => - ann.tree.retainedElems match - case ref :: Nil if ref.symbol == defn.captureRoot => Str("=>") + ann.tree.retainedSet.retainedElementsRaw match + case (ref: TermRef) :: Nil if ref.symbol == defn.captureRoot => Str("=>") case refs => Str("->") ~ toTextRetainedElems(refs) case _ => if Feature.pureFunsEnabled then "->" else "=>" diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala index 035f1fa1ab48..ecde64a720aa 100644 --- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala +++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala @@ -208,7 +208,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe case UnstableInlineAccessorID // errorNumber: 192 case VolatileOnValID // errorNumber: 193 case ExtensionNullifiedByMemberID // errorNumber: 194 - case ConstructorProxyNotValueID // errorNumber: 195 + case PhantomSymbolNotValueID // errorNumber: 195 case ContextBoundCompanionNotValueID // errorNumber: 196 case InlinedAnonClassWarningID // errorNumber: 197 case UnusedSymbolID // errorNumber: 198 diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index 7e9cff590b69..44b97790c849 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -3277,7 +3277,7 @@ extends SyntaxMsg(VolatileOnValID): protected def explain(using Context): String = "" class ConstructorProxyNotValue(sym: Symbol)(using Context) -extends TypeMsg(ConstructorProxyNotValueID): +extends TypeMsg(PhantomSymbolNotValueID): protected def msg(using Context): String = i"constructor proxy $sym cannot be used as a value" protected def explain(using Context): String = @@ -3292,7 +3292,7 @@ extends TypeMsg(ConstructorProxyNotValueID): |but not as a stand-alone value.""" class ContextBoundCompanionNotValue(sym: Symbol)(using Context) -extends TypeMsg(ConstructorProxyNotValueID): +extends TypeMsg(PhantomSymbolNotValueID): protected def msg(using Context): String = i"context bound companion $sym cannot be used as a value" protected def explain(using Context): String = @@ -3311,6 +3311,22 @@ extends TypeMsg(ConstructorProxyNotValueID): |companion value with the (term-)name `A`. However, these context bound companions |are not values themselves, they can only be referred to in selections.""" +class DummyCaptureParamNotValue(sym: Symbol)(using Context) +extends TypeMsg(PhantomSymbolNotValueID): + protected def msg(using Context): String = + i"dummy term capture parameter $sym cannot be used as a value" + protected def explain(using Context): String = + i"""A term capture parameter is a symbol made up by the compiler to represent a reference + |to a real capture parameter in capture sets. For instance, in + | + | class A: + | type C^ + | + |there is just a type `A` declared but not a value `A`. Nevertheless, one can write + |the selection `(a: A).C` and use a a value, which works because the compiler created a + |term capture parameter for `C`. However, these term capture parameters are not real values, + |they can only be referred in capture sets.""" + class UnusedSymbol(errorText: String, val actions: List[CodeAction] = Nil)(using Context) extends Message(UnusedSymbolID): def kind = MessageKind.UnusedSymbol @@ -3518,7 +3534,7 @@ final class OnlyFullyDependentAppliedConstructorType()(using Context) override protected def explain(using Context): String = "" final class IllegalContextBounds(using Context) extends SyntaxMsg(IllegalContextBoundsID): - override protected def msg(using Context): String = + override protected def msg(using Context): String = i"Context bounds are not allowed in this position" override protected def explain(using Context): String = "" diff --git a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala index 05dff8ffadbc..df6075ee3990 100644 --- a/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala +++ b/compiler/src/dotty/tools/dotc/semanticdb/ExtractSemanticDB.scala @@ -262,7 +262,7 @@ object ExtractSemanticDB: private def excludeSymbol(sym: Symbol)(using Context): Boolean = !sym.exists - || sym.is(ConstructorProxy) + || sym.is(PhantomSymbol) || sym.name.isWildcard || excludeQual(sym) diff --git a/compiler/src/dotty/tools/dotc/transform/Getters.scala b/compiler/src/dotty/tools/dotc/transform/Getters.scala index a58dffa04223..6e6d84a9eaae 100644 --- a/compiler/src/dotty/tools/dotc/transform/Getters.scala +++ b/compiler/src/dotty/tools/dotc/transform/Getters.scala @@ -89,7 +89,8 @@ class Getters extends MiniPhase with SymTransformer { thisPhase => else d1 = d1.copySymDenotation(initFlags = d1.flags &~ Local) d1 } - private val NoGetterNeededFlags = Method | Param | JavaDefined | JavaStatic + + private val NoGetterNeededFlags = Method | Param | JavaDefined | JavaStatic | PhantomSymbol val newSetters = util.HashSet[Symbol]() diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index f970e75177e3..9ea8a5e7969c 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -196,7 +196,10 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => val saved = inJavaAnnot inJavaAnnot = annot.symbol.is(JavaDefined) if (inJavaAnnot) checkValidJavaAnnotation(annot) - try transform(annot) + try + val annotCtx = if annot.hasAttachment(untpd.RetainsAnnot) + then ctx.addMode(Mode.InCaptureSet) else ctx + transform(annot)(using annotCtx) finally inJavaAnnot = saved } @@ -346,8 +349,11 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => def checkUsableAsValue(tree: Tree)(using Context): Tree = def unusable(msg: Symbol => Message) = errorTree(tree, msg(tree.symbol)) - if tree.symbol.is(ConstructorProxy) then - unusable(ConstructorProxyNotValue(_)) + if tree.symbol.is(PhantomSymbol) then + if tree.symbol.isDummyCaptureParam then + unusable(DummyCaptureParamNotValue(_)) + else + unusable(ConstructorProxyNotValue(_)) else if tree.symbol.isContextBoundCompanion then unusable(ContextBoundCompanionNotValue(_)) else @@ -704,7 +710,6 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => case _ => if parents1 ne info.parents then info.derivedClassInfo(declaredParents = parents1) else tp - case _ if sym.is(ConstructorProxy) => NoType case _ => tp private def argTypeOfCaseClassThatNeedsAbstractFunction1(sym: Symbol)(using Context): Option[List[Type]] = diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index ac1ef34f5ef8..b43acce78d35 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -63,7 +63,7 @@ class TreeChecker extends Phase with SymTransformer { } if (prev.exists) - assert(cur.exists || prev.is(ConstructorProxy), i"companion disappeared from $symd") + assert(cur.exists || prev.is(PhantomSymbol), i"companion disappeared from $symd") } def transformSym(symd: SymDenotation)(using Context): SymDenotation = { @@ -387,7 +387,7 @@ object TreeChecker { } def isSymWithoutDef(sym: Symbol)(using Context): Boolean = - sym.is(ConstructorProxy) || sym.isContextBoundCompanion + sym.is(PhantomSymbol) || sym.isContextBoundCompanion /** Exclude from double definition checks any erased symbols that were * made `private` in phase `UnlinkErasedDecls`. These symbols will be removed diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 78e2099511d7..de31936b6e42 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -1117,9 +1117,7 @@ trait Applications extends Compatibility { val fun2 = Applications.retypeSignaturePolymorphicFn(fun1, methType) simpleApply(fun2, proto) case funRef: TermRef => - // println(i"typedApply: $funRef, ${tree.args}, ${funRef.symbol.maybeOwner.isRetains}") - val applyCtx = if funRef.symbol.maybeOwner.isRetains then ctx.addMode(Mode.InCaptureSet) else ctx - val app = ApplyTo(tree, fun1, funRef, proto, pt)(using applyCtx) + val app = ApplyTo(tree, fun1, funRef, proto, pt) convertNewGenericArray( widenEnumCase( postProcessByNameArgs(funRef, app).computeNullable(), @@ -2112,8 +2110,8 @@ trait Applications extends Compatibility { else 0 end compareWithTypes - if alt1.symbol.is(ConstructorProxy) && !alt2.symbol.is(ConstructorProxy) then -1 - else if alt2.symbol.is(ConstructorProxy) && !alt1.symbol.is(ConstructorProxy) then 1 + if alt1.symbol.is(PhantomSymbol) && !alt2.symbol.is(PhantomSymbol) then -1 + else if alt2.symbol.is(PhantomSymbol) && !alt1.symbol.is(PhantomSymbol) then 1 else val fullType1 = widenGiven(alt1.widen, alt1) val fullType2 = widenGiven(alt2.widen, alt2) diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index a0e06cc7119d..46657d8ee8bb 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -140,7 +140,7 @@ class Namer { typer: Typer => def conflict(conflicting: Symbol) = val other = - if conflicting.is(ConstructorProxy) then conflicting.companionClass + if conflicting.is(PhantomSymbol) then conflicting.companionClass else conflicting report.error(AlreadyDefined(name, owner, other), ctx.source.atSpan(span)) conflictsDetected = true @@ -947,7 +947,7 @@ class Namer { typer: Typer => !sd.symbol.is(Deferred) && sd.matches(denot))) val isClashingSynthetic = - denot.is(Synthetic, butNot = ConstructorProxy) && + denot.is(Synthetic, butNot = PhantomSymbol) && ( (desugar.isRetractableCaseClassMethodName(denot.name) && isCaseClassOrCompanion(denot.owner) @@ -1134,6 +1134,9 @@ class Namer { typer: Typer => ensureUpToDate(sym.typeRef, dummyInfo1) if (dummyInfo2 `ne` dummyInfo1) ensureUpToDate(sym.typeRef, dummyInfo2) + if original.hasAttachment(Trees.CaptureVar) then + addDummyTermCaptureParam(sym)(using ictx) + sym.info end typeSig } @@ -1197,7 +1200,7 @@ class Namer { typer: Typer => case _ => false if !sym.isAccessibleFrom(pathType) then No("is not accessible") - else if sym.isConstructor || sym.is(ModuleClass) || sym.is(Bridge) || sym.is(ConstructorProxy) || sym.isAllOf(JavaModule) then + else if sym.isConstructor || sym.is(ModuleClass) || sym.is(Bridge) || sym.is(PhantomSymbol) || sym.isAllOf(JavaModule) then Skip // if the cls is a subclass or mixes in the owner of the symbol // and either @@ -1390,7 +1393,7 @@ class Namer { typer: Typer => def addWildcardForwardersNamed(name: TermName, span: Span): Unit = List(name, name.toTypeName) - .flatMap(pathType.memberBasedOnFlags(_, excluded = Private|Given|ConstructorProxy).alternatives) + .flatMap(pathType.memberBasedOnFlags(_, excluded = Private|Given|PhantomSymbol).alternatives) .foreach(addForwarder(name, _, span)) // ignore if any are not added def addWildcardForwarders(seen: List[TermName], span: Span): Unit = diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index c500b6cc60bb..cc5e16029314 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -434,13 +434,12 @@ object RefChecks { } def emitOverrideError(fullmsg: Message) = - if (!(hasErrors && member.is(Synthetic) && member.is(Module))) { - // suppress errors relating toi synthetic companion objects if other override + if !(hasErrors && member.is(Synthetic) && member.is(Module) || member.isDummyCaptureParam) then + // suppress errors relating to synthetic companion objects if other override // errors (e.g. relating to the companion class) have already been reported. if (member.owner == clazz) report.error(fullmsg, member.srcPos) else mixinOverrideErrors += new MixinOverrideError(member, fullmsg) hasErrors = true - } def overrideError(msg: String, compareTypes: Boolean = false) = if trueMatch && noErrorType then diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 30d3add2529f..e706448fc87b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -210,7 +210,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer altImports: mutable.ListBuffer[TermRef] | Null = null)(using Context): Type = { val refctx = ctx val noImports = ctx.mode.is(Mode.InPackageClauseName) - def suppressErrors = excluded.is(ConstructorProxy) + def suppressErrors = excluded.is(PhantomSymbol) // when searching for references shadowed by a constructor proxy, do not report errors def fail(msg: Message) = if !suppressErrors then report.error(msg, pos) @@ -649,8 +649,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer */ def checkNotShadowed(ownType: Type): Type = ownType match - case ownType: TermRef if ownType.symbol.is(ConstructorProxy) => - findRef(name, pt, EmptyFlags, ConstructorProxy, tree.srcPos) match + case ownType: TermRef + if ownType.symbol.is(PhantomSymbol) + && !(ctx.mode.is(Mode.InCaptureSet) && ownType.symbol.isDummyCaptureParam) => + findRef(name, pt, EmptyFlags, PhantomSymbol, tree.srcPos) match case shadowed: TermRef if !shadowed.symbol.maybeOwner.isEmptyPackage => pt match case pt: FunOrPolyProto => @@ -715,10 +717,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer && ctx.owner.owner.unforcedDecls.lookup(tree.name).exists then // we are in the arguments of a this(...) constructor call errorTree(tree, em"$tree is not accessible from constructor arguments") - else if name.isTermName && ctx.mode.is(Mode.InCaptureSet) then - // If we are in a capture set and the identifier is not a term name, - // try to type it with the same name but as a type - typed(untpd.makeCapsOf(untpd.cpy.Ident(tree)(name.toTypeName)), pt) else errorTree(tree, MissingIdent(tree, kind, name, pt)) end typedIdent @@ -924,13 +922,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer typedCBSelect(tree0, pt, qual) else EmptyTree - // Otherwise, if we are in a capture set, try to type it as a capture variable - // reference (as selecting a type name). - def trySelectTypeInCaptureSet() = - if tree0.name.isTermName && ctx.mode.is(Mode.InCaptureSet) then - typedSelectWithAdapt(untpd.cpy.Select(tree0)(qual, tree0.name.toTypeName), pt, qual) - else EmptyTree - // Otherwise, report an error def reportAnError() = assignType(tree, @@ -952,7 +943,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer .orElse(tryDynamic()) .orElse(trySelectable()) .orElse(tryCBCompanion()) - .orElse(trySelectTypeInCaptureSet()) .orElse(reportAnError()) end typedSelectWithAdapt @@ -2541,8 +2531,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer errorTree(tree, em"Illegal context bound: ${tycon.tpe} does not take type parameters$selfNote.") - def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(using Context): SingletonTypeTree = { + def typedSingletonTypeTree(tree: untpd.SingletonTypeTree)(using Context): Tree = { val ref1 = typedExpr(tree.ref, SingletonTypeProto) + if ctx.mode.is(Mode.InCaptureSet) && ref1.symbol.isDummyCaptureParam then + // When a dummy term capture variable is found, it is replaced with + // the corresponding type references (stored in the underling types). + return Ident(ref1.tpe.widen.asInstanceOf[TypeRef]).withSpan(tree.span) checkStable(ref1.tpe, tree.srcPos, "singleton type") assignType(cpy.SingletonTypeTree(tree)(ref1), ref1) } @@ -3431,7 +3425,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer end typedPackageDef def typedAnnotated(tree: untpd.Annotated, pt: Type)(using Context): Tree = { - val annot0 = withMode(Mode.InAnnotation)(typedExpr(tree.annot)) + var annotCtx = ctx.addMode(Mode.InAnnotation) + if tree.annot.hasAttachment(untpd.RetainsAnnot) then + annotCtx = annotCtx.addMode(Mode.InCaptureSet) + val annot0 = typedExpr(tree.annot)(using annotCtx) val annot1 = checkAnnotClass(annot0) val annotCls = Annotations.annotClass(annot1) if annotCls == defn.NowarnAnnot then @@ -4543,15 +4540,10 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer true } - def isRetainsArg(pt: Type) = pt match - case AnnotatedType(arg, annot) => annot.symbol == defn.RetainsArgAnnot - case _ => false - if (implicitFun || caseCompanion) && !isApplyProto(pt) && pt != SingletonTypeProto && pt != LhsProto - && !isRetainsArg(pt) && !ctx.mode.is(Mode.Pattern) && !tree.isInstanceOf[SplicePattern] && !ctx.isAfterTyper diff --git a/library/src/scala/annotation/retains.scala b/library/src/scala/annotation/retains.scala index 9c4af7f2336d..05896b117796 100644 --- a/library/src/scala/annotation/retains.scala +++ b/library/src/scala/annotation/retains.scala @@ -2,7 +2,7 @@ package scala.annotation /** An annotation that indicates capture of a set of references under capture checking. * - * T @retains(x, y, z) + * T @retains[x.type | y.type | z.type] * * is the internal representation used for the capturing type * @@ -12,20 +12,11 @@ package scala.annotation * non-standard capturing type syntax. */ @experimental -class retains(xs: (Any@retainsArg)*) extends annotation.StaticAnnotation +class retains[Elems] extends annotation.StaticAnnotation -/** Equivalent in meaning to `@retains(cap)`, but consumes less bytecode. +/** Equivalent in meaning to `@retains[cap.type]`, but consumes less bytecode. */ @experimental -class retainsCap() extends annotation.StaticAnnotation +class retainsCap extends annotation.StaticAnnotation // This special case is needed to be able to load standard library modules without // cyclic reference errors. Specifically, load sequences involving IterableOnce. - -/** Internal use, only for parameters of `retains` and `retainsByName`. - */ -@experimental -class retainsArg extends annotation.StaticAnnotation - // This annotation prevents argument references to retains and retainsByName from being - // augmented with explicit arguments. That's unsound in general, but necessary - // since a captureRef could have an impure context function type, A ?=> B, but - // we still need to have the unapplied captureRef in the annotation. diff --git a/library/src/scala/annotation/retainsByName.scala b/library/src/scala/annotation/retainsByName.scala index e6e3dafcb752..acc8ec664af3 100644 --- a/library/src/scala/annotation/retainsByName.scala +++ b/library/src/scala/annotation/retainsByName.scala @@ -2,5 +2,5 @@ package scala.annotation /** An annotation that indicates capture of an enclosing by-name type */ -@experimental class retainsByName(xs: (Any@retainsArg)*) extends annotation.StaticAnnotation +@experimental class retainsByName[Elems] extends annotation.StaticAnnotation diff --git a/library/src/scala/caps/package.scala b/library/src/scala/caps/package.scala index 3016cb4ebe14..fedfd7400e25 100644 --- a/library/src/scala/caps/package.scala +++ b/library/src/scala/caps/package.scala @@ -88,24 +88,6 @@ sealed trait Exists extends Capability @experimental object internal: - /** A wrapper indicating a type variable in a capture argument list of a - * @retains annotation. E.g. `^{x, Y^}` is represented as `@retains(x, capsOf[Y])`. - */ - @compileTimeOnly("Should be be used only internally by the Scala compiler") - def capsOf[CS >: CapSet <: CapSet @retainsCap]: Any = ??? - - /** Reach capabilities x* which appear as terms in @retains annotations are encoded - * as `caps.reachCapability(x)`. When converted to CaptureRef types in capture sets - * they are represented as `x.type @annotation.internal.reachCapability`. - */ - extension (x: Any) def reachCapability: Any = x - - /** Read-only capabilities x.rd which appear as terms in @retains annotations are encoded - * as `caps.readOnlyCapability(x)`. When converted to CaptureRef types in capture sets - * they are represented as `x.type @annotation.internal.readOnlyCapability`. - */ - extension (x: Any) def readOnlyCapability: Any = x - /** An internal annotation placed on a refinement created by capture checking. * Refinements with this annotation unconditionally override any * info from the parent type, so no intersection needs to be formed. diff --git a/tests/disabled/neg-custom-args/captures/capt-wf.scala b/tests/disabled/neg-custom-args/captures/capt-wf.scala index 302202064ac0..fe04d6709f91 100644 --- a/tests/disabled/neg-custom-args/captures/capt-wf.scala +++ b/tests/disabled/neg-custom-args/captures/capt-wf.scala @@ -1,17 +1,17 @@ // No longer valid class C -type Cap = C @retains(caps.cap) -type Top = Any @retains(caps.cap) +type Cap = C @retains[caps.cap.type] +type Top = Any @retains[caps.cap.type] -type T = (x: Cap) => List[String @retains(x)] => Unit // error -val x: (x: Cap) => Array[String @retains(x)] = ??? // error +type T = (x: Cap) => List[String @retains[x.type]] => Unit // error +val x: (x: Cap) => Array[String @retains[x.type]] = ??? // error val y = x def test: Unit = def f(x: Cap) = // ok - val g = (xs: List[String @retains(x)]) => () + val g = (xs: List[String @retains[x.type]]) => () g - def f2(x: Cap)(xs: List[String @retains(x)]) = () + def f2(x: Cap)(xs: List[String @retains[x.type]]) = () val x = f // error val x2 = f2 // error val y = f(C()) // ok diff --git a/tests/disabled/neg-custom-args/captures/try2.scala b/tests/disabled/neg-custom-args/captures/try2.scala index 43e17d8c9eef..0687173b4d3d 100644 --- a/tests/disabled/neg-custom-args/captures/try2.scala +++ b/tests/disabled/neg-custom-args/captures/try2.scala @@ -5,7 +5,7 @@ import annotation.ability @ability erased val canThrow: * = ??? class CanThrow[E <: Exception] extends Retains[canThrow.type] -type Top = Any @retains(caps.cap) +type Top = Any @retains[caps.cap.type] infix type throws[R, E <: Exception] = (erased CanThrow[E]) ?=> R diff --git a/tests/neg-custom-args/boxmap.scala b/tests/neg-custom-args/boxmap.scala index 1696ac3505e4..5a91947edba3 100644 --- a/tests/neg-custom-args/boxmap.scala +++ b/tests/neg-custom-args/boxmap.scala @@ -1,5 +1,5 @@ import annotation.retains -type Top = Any @retains(caps.cap) +type Top = Any @retains[caps.cap.type] type Box[+T <: Top] = ([K <: Top] -> (T => K) -> K) diff --git a/tests/neg-custom-args/captures/branding.scala b/tests/neg-custom-args/captures/branding.scala index 7b722971e670..b59677487eb5 100644 --- a/tests/neg-custom-args/captures/branding.scala +++ b/tests/neg-custom-args/captures/branding.scala @@ -11,7 +11,7 @@ def main() = def log(msg: String): Unit // we can close over anything subsumed by the 'trusted' brand capability, but nothing else - def runSecure[C >: {trusted} <: {trusted}](block: () ->{C} Unit): Unit = block() + def runSecure[C^ >: {trusted} <: {trusted}](block: () ->{C} Unit): Unit = block() // This is a 'brand" capability to mark what can be mentioned in trusted code object trusted extends caps.Capability diff --git a/tests/neg-custom-args/captures/capset-bound.scala b/tests/neg-custom-args/captures/capset-bound.scala index 71250ec1585e..ad79e1a8e6c1 100644 --- a/tests/neg-custom-args/captures/capset-bound.scala +++ b/tests/neg-custom-args/captures/capset-bound.scala @@ -7,7 +7,6 @@ case class File(io: IO^) def test(io1: IO^, io2: IO^) = def f[C^ >: {io1}](file: File^{C}) = ??? - def g[C >: {io1}](file: File^{C}) = ??? val f1: File^{io1} = ??? val f2: File^{io2} = ??? val f3: File^{io1, io2} = ??? @@ -17,11 +16,4 @@ def test(io1: IO^, io2: IO^) = f[{io2}](f2) // error f[{io1, io2}](f1) f[{io1, io2}](f2) - f[{io1, io2}](f3) - g[{io1}](f1) - g[{io1}](f2) // error - g[{io1}](f3) // error - g[{io2}](f2) // error - g[{io1, io2}](f1) - g[{io1, io2}](f2) - g[{io1, io2}](f3) \ No newline at end of file + f[{io1, io2}](f3) \ No newline at end of file diff --git a/tests/neg-custom-args/captures/capset-members-nohat.scala b/tests/neg-custom-args/captures/capset-members-nohat.scala index f99c47f23ac0..3d931200f326 100644 --- a/tests/neg-custom-args/captures/capset-members-nohat.scala +++ b/tests/neg-custom-args/captures/capset-members-nohat.scala @@ -2,7 +2,7 @@ import language.experimental.captureChecking import caps.* trait Abstract[X^]: - type C >: {X} + type C^ >: {X} // Don't test the return type using Unit, because it is a pure type. def boom(): AnyRef^{C} diff --git a/tests/neg-custom-args/captures/capset-members.scala b/tests/neg-custom-args/captures/capset-members.scala index 3d931200f326..1dddef3e5ca3 100644 --- a/tests/neg-custom-args/captures/capset-members.scala +++ b/tests/neg-custom-args/captures/capset-members.scala @@ -27,4 +27,4 @@ class Concrete5(a: AnyRef^, b: AnyRef^) extends Abstract[{a}]: def boom(): AnyRef^{b} = b // error class Concrete6(a: AnyRef^, b: AnyRef^) extends Abstract[{a}]: - def boom(): AnyRef^{b} = b // error \ No newline at end of file + def boom(): AnyRef^{b} = b // error diff --git a/tests/neg-custom-args/captures/capset-members4.scala b/tests/neg-custom-args/captures/capset-members4.scala index bdce213e7de1..698ef28c1fb4 100644 --- a/tests/neg-custom-args/captures/capset-members4.scala +++ b/tests/neg-custom-args/captures/capset-members4.scala @@ -8,7 +8,7 @@ def test = def onlyWithZ[C^](using c: Contains[C, z.type]) = ??? trait Foo: - type C >: {z,x} <: {x,y,z} + type C^ >: {z,x} <: {x,y,z} val foo: Foo = ??? onlyWithZ[{foo.C}] diff --git a/tests/neg-custom-args/captures/capset-members5.scala b/tests/neg-custom-args/captures/capset-members5.scala index a779e9041a48..f79eb9df5c7c 100644 --- a/tests/neg-custom-args/captures/capset-members5.scala +++ b/tests/neg-custom-args/captures/capset-members5.scala @@ -10,22 +10,22 @@ def test = val z: Any^ = ??? trait CaptureSet: type A^ >: {y} <: {x} - type B = {x} - type C <: {x} + type B^ = {x} + type C^ <: {x} type D^ : Ctx // error - type E <: {C} - type F <: {C} - type G <: {x, y} - type H >: {x} <: {x,y} : Ctx // error + type E^ <: {C} + type F^ <: {C} + type G^ <: {x, y} + type H^ >: {x} <: {x,y} : Ctx // error type I^ = {y, G, H} type J = {O.z} type K^ = {x, O.z} - type L <: {x, y, O.z} - type M >: {x, y, O.z} <: {C} - type N >: {x} <: {x} - type O >: {O.z} <: {O.z} - type P >: {B,D} // error - type Q >: {E} <: Int // error + type L^ <: {x, y, O.z} + type M^ >: {x, y, O.z} <: {C} + type N^ >: {x} <: {x} + type O^ >: {O.z} <: {O.z} + type P^ >: {B,D} // error + type Q^ >: {E} <: Int // error type R^ >: {E} <: Int // error type S^ >: Nothing <: Int // error type T >: Nothing <: Int \ No newline at end of file diff --git a/tests/neg-custom-args/captures/capt-depfun.scala b/tests/neg-custom-args/captures/capt-depfun.scala index 384c403bdd27..d9033c9e5264 100644 --- a/tests/neg-custom-args/captures/capt-depfun.scala +++ b/tests/neg-custom-args/captures/capt-depfun.scala @@ -2,10 +2,10 @@ import annotation.retains class C -type Cap = C @retains(caps.cap) +type Cap = C @retains[caps.cap.type] class Str def f(y: Cap, z: Cap) = - def g(): C @retains(y, z) = ??? - val ac: ((x: Cap) => Str @retains(x) => Str @retains(x)) = ??? + def g(): C @retains[y.type | z.type] = ??? + val ac: ((x: Cap) => Str @retains[x.type] => Str @retains[x.type]) = ??? val dc: ((Str^{y, z}) => Str^{y, z}) = ac(g()) // error // error: separatioon diff --git a/tests/neg-custom-args/captures/capt-depfun2.scala b/tests/neg-custom-args/captures/capt-depfun2.scala index cb4bc5f9634d..d5ea3b05f168 100644 --- a/tests/neg-custom-args/captures/capt-depfun2.scala +++ b/tests/neg-custom-args/captures/capt-depfun2.scala @@ -1,11 +1,11 @@ import annotation.retains class C -type Cap = C @retains(caps.cap) +type Cap = C @retains[caps.cap.type] class Str def f(y: Cap, z: Cap) = - def g(): C @retains(y, z) = ??? - val ac: ((x: Cap) => Array[Str @retains(x)]) = ??? + def g(): C @retains[y.type | z.type] = ??? + val ac: ((x: Cap) => Array[Str @retains[x.type]]) = ??? val dc = ac(g()) // error: Needs explicit type Array[? >: Str <: {y, z} Str] // This is a shortcoming of rechecking since the originally inferred // type is `Array[Str]` and the actual type after rechecking diff --git a/tests/neg-custom-args/captures/capt-test.scala b/tests/neg-custom-args/captures/capt-test.scala index f200bb6083b5..3d5ebd3ee6ff 100644 --- a/tests/neg-custom-args/captures/capt-test.scala +++ b/tests/neg-custom-args/captures/capt-test.scala @@ -2,8 +2,8 @@ import annotation.retains import language.experimental.erasedDefinitions class CT[E <: Exception] -type CanThrow[E <: Exception] = CT[E] @retains(caps.cap) -type Top = Any @retains(caps.cap) +type CanThrow[E <: Exception] = CT[E] @retains[caps.cap.type] +type Top = Any @retains[caps.cap.type] infix type throws[R, E <: Exception] = (erased CanThrow[E]) ?=> R @@ -14,7 +14,7 @@ def raise[E <: Exception](e: E): Nothing throws E = throw e def foo(x: Boolean): Int throws Fail = if x then 1 else raise(Fail()) -def handle[E <: Exception, R <: Top](op: (CT[E] @retains(caps.cap)) => R)(handler: E => R): R = +def handle[E <: Exception, R <: Top](op: (CT[E] @retains[caps.cap.type]) => R)(handler: E => R): R = val x: CT[E] = ??? try op(x) catch case ex: E => handler(ex) diff --git a/tests/neg-custom-args/captures/capt-wf-typer.scala b/tests/neg-custom-args/captures/capt-wf-typer.scala index 09b2841d3c77..e01cc5f0e9b4 100644 --- a/tests/neg-custom-args/captures/capt-wf-typer.scala +++ b/tests/neg-custom-args/captures/capt-wf-typer.scala @@ -6,6 +6,6 @@ object foo def test(c: Cap, other: String): Unit = val x7: String^{c} = ??? // OK - val x8: String @retains(x7 + x7) = ??? // error - val x9: String @retains(foo) = ??? // error + val x8: String @retains[""] = ??? // error + val x9: String @retains[foo] = ??? // error () \ No newline at end of file diff --git a/tests/neg-custom-args/captures/capt1.check b/tests/neg-custom-args/captures/capt1.check index b0a27b134b60..68047cb32429 100644 --- a/tests/neg-custom-args/captures/capt1.check +++ b/tests/neg-custom-args/captures/capt1.check @@ -54,8 +54,8 @@ | | longer explanation available when compiling with `-explain` -- Error: tests/neg-custom-args/captures/capt1.scala:38:13 ------------------------------------------------------------- -38 | val z3 = h[(() -> Cap) @retains(x)](() => x)(() => C()) // error - | ^^^^^^^^^^^^^^^^^^^^^^^ +38 | val z3 = h[(() -> Cap) @retains[x.type]](() => x)(() => C()) // error + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | Type variable X of method h cannot be instantiated to box () ->{x} C^ since | the part C^ of that type captures the root capability `cap`. | diff --git a/tests/neg-custom-args/captures/capt1.scala b/tests/neg-custom-args/captures/capt1.scala index 48778dbd6716..7b612363958e 100644 --- a/tests/neg-custom-args/captures/capt1.scala +++ b/tests/neg-custom-args/captures/capt1.scala @@ -1,22 +1,22 @@ import annotation.retains class C -def f(x: C @retains(caps.cap), y: C): () -> C = +def f(x: C @retains[caps.cap.type], y: C): () -> C = () => if x == null then y else y // error -def g(x: C @retains(caps.cap), y: C): Matchable = +def g(x: C @retains[caps.cap.type], y: C): Matchable = () => if x == null then y else y // error -def h1(x: C @retains(caps.cap), y: C): Any = +def h1(x: C @retains[caps.cap.type], y: C): Any = def f() = if x == null then y else y () => f() // ok -def h2(x: C @retains(caps.cap)): Matchable = +def h2(x: C @retains[caps.cap.type]): Matchable = def f(y: Int) = if x == null then y else y // error f class A -type Cap = C @retains(caps.cap) +type Cap = C @retains[caps.cap.type] def h3(x: Cap): A = class F(y: Int) extends A: // error @@ -30,12 +30,12 @@ def h4(x: Cap, y: Int): A = def f1(c: Cap): () ->{c} c.type = () => c // ok def foo() = - val x: C @retains(caps.cap) = ??? + val x: C @retains[caps.cap.type] = ??? def h[X](a: X)(b: X) = a val z2 = h[() -> Cap](() => x) // error // error (() => C()) - val z3 = h[(() -> Cap) @retains(x)](() => x)(() => C()) // error + val z3 = h[(() -> Cap) @retains[x.type]](() => x)(() => C()) // error val z1: () => Cap = f1(x) diff --git a/tests/neg-custom-args/captures/capt3.scala b/tests/neg-custom-args/captures/capt3.scala index 44a7ffdc6c4a..a9329a9e4290 100644 --- a/tests/neg-custom-args/captures/capt3.scala +++ b/tests/neg-custom-args/captures/capt3.scala @@ -1,6 +1,6 @@ import annotation.retains class C -type Cap = C @retains(caps.cap) +type Cap = C @retains[caps.cap.type] def test1() = val x: Cap = C() diff --git a/tests/neg-custom-args/captures/capture-parameters.scala b/tests/neg-custom-args/captures/capture-parameters.scala index d9288a062ded..8f5de6346268 100644 --- a/tests/neg-custom-args/captures/capture-parameters.scala +++ b/tests/neg-custom-args/captures/capture-parameters.scala @@ -2,7 +2,7 @@ import caps.* class C -def test[X^, Y^, Z >: X <: Y](x: C^{X}, y: C^{Y}, z: C^{Z}) = +def test[X^, Y^, Z^ >: X <: Y](x: C^{X}, y: C^{Y}, z: C^{Z}) = val x2z: C^{Z} = x val z2y: C^{Y} = z val x2y: C^{Y} = x // error diff --git a/tests/neg-custom-args/captures/cc-this3.check b/tests/neg-custom-args/captures/cc-this3.check index cdd91767ce22..6199a39bed17 100644 --- a/tests/neg-custom-args/captures/cc-this3.check +++ b/tests/neg-custom-args/captures/cc-this3.check @@ -1,5 +1,5 @@ --- [E058] Type Mismatch Error: tests/neg-custom-args/captures/cc-this3.scala:8:6 --------------------------------------- -8 |class B extends A: // error +-- [E058] Type Mismatch Error: tests/neg-custom-args/captures/cc-this3.scala:9:6 --------------------------------------- +9 |class B extends A: // error | ^ | illegal inheritance: self type B^ of class B does not conform to self type A^{} | of parent class A @@ -7,8 +7,8 @@ | where: ^ refers to the universal root capability | | longer explanation available when compiling with `-explain` --- [E058] Type Mismatch Error: tests/neg-custom-args/captures/cc-this3.scala:11:6 -------------------------------------- -11 |class C(val f: () => Int) extends A // error +-- [E058] Type Mismatch Error: tests/neg-custom-args/captures/cc-this3.scala:12:6 -------------------------------------- +12 |class C(val f: () => Int) extends A // error | ^ | illegal inheritance: self type C^{C.this.f} of class C does not conform to self type A^{} | of parent class A diff --git a/tests/neg-custom-args/captures/cc-this3.scala b/tests/neg-custom-args/captures/cc-this3.scala index 0a36cde8173b..c3d751b12f67 100644 --- a/tests/neg-custom-args/captures/cc-this3.scala +++ b/tests/neg-custom-args/captures/cc-this3.scala @@ -1,3 +1,4 @@ +import language.experimental.captureChecking class Cap extends caps.Capability def eff(using Cap): Unit = () diff --git a/tests/neg-custom-args/captures/cc1.scala b/tests/neg-custom-args/captures/cc1.scala index 6787b417a3b2..cc2c5bde3220 100644 --- a/tests/neg-custom-args/captures/cc1.scala +++ b/tests/neg-custom-args/captures/cc1.scala @@ -1,5 +1,10 @@ +import language.experimental.captureChecking import annotation.retains +import annotation.retainsCap + object Test: - def f[A <: Matchable @retains(caps.cap)](x: A): Matchable = x // error + def f[A <: Matchable @retains[caps.cap.type]](x: A): Matchable = x // error + + def g[A <: Matchable @retainsCap](x: A): Matchable = x // error diff --git a/tests/neg-custom-args/captures/check-dummy-symbol.check b/tests/neg-custom-args/captures/check-dummy-symbol.check new file mode 100644 index 000000000000..345934089910 --- /dev/null +++ b/tests/neg-custom-args/captures/check-dummy-symbol.check @@ -0,0 +1,12 @@ +-- [E195] Type Error: tests/neg-custom-args/captures/check-dummy-symbol.scala:6:21 ------------------------------------- +6 |def f(a: A): a.C = a.C // error + | ^^^ + | dummy term capture parameter value C cannot be used as a value + | + | longer explanation available when compiling with `-explain` +-- [E195] Type Error: tests/neg-custom-args/captures/check-dummy-symbol.scala:7:15 ------------------------------------- +7 |def g[C^]: C = C // error + | ^ + | dummy term capture parameter value C cannot be used as a value + | + | longer explanation available when compiling with `-explain` diff --git a/tests/neg-custom-args/captures/check-dummy-symbol.scala b/tests/neg-custom-args/captures/check-dummy-symbol.scala new file mode 100644 index 000000000000..c2cafcc14cf1 --- /dev/null +++ b/tests/neg-custom-args/captures/check-dummy-symbol.scala @@ -0,0 +1,7 @@ +import language.experimental.captureChecking + +class A: + type C^ + +def f(a: A): a.C = a.C // error +def g[C^]: C = C // error \ No newline at end of file diff --git a/tests/neg-custom-args/captures/io.scala b/tests/neg-custom-args/captures/io.scala index f481bf357fc8..4869a2c89a89 100644 --- a/tests/neg-custom-args/captures/io.scala +++ b/tests/neg-custom-args/captures/io.scala @@ -3,17 +3,17 @@ sealed trait IO: def puts(msg: Any): Unit = println(msg) def test1 = - val IO : IO @retains(caps.cap) = new IO {} + val IO : IO @retains[caps.cap.type] = new IO {} def foo = {IO; IO.puts("hello") } val x : () -> Unit = () => foo // error: Found: (() -> Unit) retains IO; Required: () -> Unit def test2 = - val IO : IO @retains(caps.cap) = new IO {} - def puts(msg: Any, io: IO @retains(caps.cap)) = println(msg) + val IO : IO @retains[caps.cap.type] = new IO {} + def puts(msg: Any, io: IO @retains[caps.cap.type]) = println(msg) def foo() = puts("hello", IO) val x : () -> Unit = () => foo() // error: Found: (() -> Unit) retains IO; Required: () -> Unit -type Capability[T] = T @retains(caps.cap) +type Capability[T] = T @retains[caps.cap.type] def test3 = val IO : Capability[IO] = new IO {} diff --git a/tests/neg-custom-args/captures/try.scala b/tests/neg-custom-args/captures/try.scala index 753958b234c5..8168504617ac 100644 --- a/tests/neg-custom-args/captures/try.scala +++ b/tests/neg-custom-args/captures/try.scala @@ -2,8 +2,8 @@ import annotation.retains import language.experimental.erasedDefinitions class CT[E <: Exception] -type CanThrow[E <: Exception] = CT[E] @retains(caps.cap) -type Top = Any @retains(caps.cap) +type CanThrow[E <: Exception] = CT[E] @retains[caps.cap.type] +type Top = Any @retains[caps.cap.type] infix type throws[R, E <: Exception] = (erased CanThrow[E]) ?=> R diff --git a/tests/pos-custom-args/captures/byname.scala b/tests/pos-custom-args/captures/byname.scala index 761496185a0d..ca1d02fb45dc 100644 --- a/tests/pos-custom-args/captures/byname.scala +++ b/tests/pos-custom-args/captures/byname.scala @@ -9,6 +9,6 @@ def test(cap1: Cap, cap2: Cap): I^{cap1} = def f() = if cap1 == cap1 then I() else I() def h(x: ->{cap} I) = x h(f()) // OK - def hh(x: -> I @retainsByName(cap1)) = x + def hh(x: -> I @retainsByName[cap1.type]) = x h(f()) diff --git a/tests/pos-custom-args/captures/cap-paramlist8-desugared.scala b/tests/pos-custom-args/captures/cap-paramlist8-desugared.scala index d34a81bcfa2f..15b829646c65 100644 --- a/tests/pos-custom-args/captures/cap-paramlist8-desugared.scala +++ b/tests/pos-custom-args/captures/cap-paramlist8-desugared.scala @@ -11,14 +11,14 @@ val z: Any^{cap} = ??? } val baz3: - Int -> [C >: caps.CapSet <: caps.CapSet^, - D >: caps.CapSet <: caps.CapSet^{C}, E >: caps.CapSet <: - caps.CapSet^{C, x}] => () -> [F >: caps.CapSet^{x, y} <: + Int -> [C^ >: caps.CapSet <: caps.CapSet^, + D^ >: caps.CapSet <: caps.CapSet^{C}, E^ >: caps.CapSet <: + caps.CapSet^{C, x}] => () -> [F^ >: caps.CapSet^{x, y} <: caps.CapSet^{C, E}] => (x: Int) -> (Ctx[F]) ?-> Int = (i: Int) => [ - C >: _root_.scala.caps.CapSet <: _root_.scala.caps.CapSet^{cap}, - D >: _root_.scala.caps.CapSet <: _root_.scala.caps.CapSet^{C}, - E >: _root_.scala.caps.CapSet <: _root_.scala.caps.CapSet^{C, x}] => + C^ >: _root_.scala.caps.CapSet <: _root_.scala.caps.CapSet^{cap}, + D^ >: _root_.scala.caps.CapSet <: _root_.scala.caps.CapSet^{C}, + E^ >: _root_.scala.caps.CapSet <: _root_.scala.caps.CapSet^{C, x}] => () => [ F >: _root_.scala.caps.CapSet^{x, y} <: diff --git a/tests/pos-custom-args/captures/cap-paramlists.scala b/tests/pos-custom-args/captures/cap-paramlists.scala index 536b7f1d739a..da9bf0779a6c 100644 --- a/tests/pos-custom-args/captures/cap-paramlists.scala +++ b/tests/pos-custom-args/captures/cap-paramlists.scala @@ -5,17 +5,17 @@ def test = val y: Any^ = ??? object O: val z: Any^ = ??? - def foo[A >: {y} <: {x}, + def foo[A^ >: {y} <: {x}, B^, - C <: {x}, + C^ <: {x}, D^, - E <: {C}, - F <: {C}, - G <: {x, y}, - H >: {x} <: {x,y}, T, U >: {x}]()[I^ <: {y, G, H}, - J <: {O.z}, - K <: {x, O.z}, - L <: {x, y, O.z}, - M >: {x, y, O.z} <: {C}, - N >: {x} <: {x}, - O >: {O.z} <: {O.z}] = ??? \ No newline at end of file + E^ <: {C}, + F^ <: {C}, + G^ <: {x, y}, + H^ >: {x} <: {x,y}, T, U >: {x}]()[I^ <: {y, G, H}, + J^ <: {O.z}, + K^ <: {x, O.z}, + L^ <: {x, y, O.z}, + M^ >: {x, y, O.z} <: {C}, + N^ >: {x} <: {x}, + O^ >: {O.z} <: {O.z}] = ??? \ No newline at end of file diff --git a/tests/pos-custom-args/captures/caps-universal.scala b/tests/pos-custom-args/captures/caps-universal.scala index 3768c640fd68..6555062395c4 100644 --- a/tests/pos-custom-args/captures/caps-universal.scala +++ b/tests/pos-custom-args/captures/caps-universal.scala @@ -1,7 +1,7 @@ import annotation.retains val foo: Int => Int = x => x -val bar: (Int -> Int) @retains(caps.cap) = foo +val bar: (Int -> Int) @retains[caps.cap.type] = foo val baz: Int => Int = bar diff --git a/tests/pos-custom-args/captures/capset-members.scala b/tests/pos-custom-args/captures/capset-members.scala index 00b6486a6819..4d05c5594dac 100644 --- a/tests/pos-custom-args/captures/capset-members.scala +++ b/tests/pos-custom-args/captures/capset-members.scala @@ -7,18 +7,18 @@ def test = val z: Any^ = ??? trait CaptureSet: type A^ >: {y} <: {x} - type B = {x} - type C <: {x} + type B^ = {x} + type C^ <: {x} type D^ - type E <: {C} - type F <: {C} - type G <: {x, y} - type H >: {x} <: {x,y} + type E^ <: {C} + type F^ <: {C} + type G^ <: {x, y} + type H^ >: {x} <: {x,y} type I^ = {y, G, H} - type J = {O.z} + type J^ = {O.z} type K^ = {x, O.z} - type L <: {x, y, O.z} - type M >: {x, y, O.z} <: {C} - type N >: {x} <: {x} - type O >: {O.z} <: {O.z} - type P >: {B,D} \ No newline at end of file + type L^ <: {x, y, O.z} + type M^ >: {x, y, O.z} <: {C} + type N^ >: {x} <: {x} + type O^ >: {O.z} <: {O.z} + type P^ >: {B,D} \ No newline at end of file diff --git a/tests/pos-custom-args/captures/capt-depfun.scala b/tests/pos-custom-args/captures/capt-depfun.scala index e3abbe0994c5..bf4fb7da2cd4 100644 --- a/tests/pos-custom-args/captures/capt-depfun.scala +++ b/tests/pos-custom-args/captures/capt-depfun.scala @@ -1,21 +1,21 @@ import annotation.retains class C -type Cap = C @retains(caps.cap) +type Cap = C @retains[caps.cap.type] -type T = (x: Cap) -> String @retains(x) +type T = (x: Cap) -> String @retains[x.type] type ID[X] = X -val aa: ((x: Cap) -> String @retains(x)) = (x: Cap) => "" +val aa: ((x: Cap) -> String @retains[x.type]) = (x: Cap) => "" -def f(y: Cap, z: Cap): String @retains(caps.cap) = - val a: ((x: Cap) -> String @retains(x)) = (x: Cap) => "" +def f(y: Cap, z: Cap): String @retains[caps.cap.type] = + val a: ((x: Cap) -> String @retains[x.type]) = (x: Cap) => "" val b = a(y) - val c: String @retains(y) = b - def g(): C @retains(y, z) = ??? + val c: String @retains[y.type] = b + def g(): C @retains[y.type | z.type] = ??? val d = a(g()) - val ac: ((x: Cap) -> ID[String @retains(x) -> String @retains(x)]) = ??? + val ac: ((x: Cap) -> ID[String @retains[x.type] -> String @retains[x.type]]) = ??? val bc: String^{y} -> String^{y} = ac(y) val dc: String -> String^{y, z} = ac(g()) c diff --git a/tests/pos-custom-args/captures/capt-depfun2.scala b/tests/pos-custom-args/captures/capt-depfun2.scala index e4645cfcc920..50b0fa9d3d99 100644 --- a/tests/pos-custom-args/captures/capt-depfun2.scala +++ b/tests/pos-custom-args/captures/capt-depfun2.scala @@ -1,9 +1,9 @@ import annotation.retains class C -type Cap = C @retains(caps.cap) +type Cap = C @retains[caps.cap.type] def f(y: Cap, z: Cap) = - def g(): C @retains(y, z) = ??? - val ac: ((x: Cap) -> Array[String @retains(x)]) = ??? + def g(): C @retains[y.type | z.type] = ??? + val ac: ((x: Cap) -> Array[String @retains[x.type]]) = ??? val dc: Array[? >: String <: String]^{y, z} = ac(g()) // needs to be inferred val ec = ac(y) diff --git a/tests/pos-custom-args/captures/capt0.scala b/tests/pos-custom-args/captures/capt0.scala index 013ff3a4ee19..ea535bbd433e 100644 --- a/tests/pos-custom-args/captures/capt0.scala +++ b/tests/pos-custom-args/captures/capt0.scala @@ -2,6 +2,6 @@ object Test: def test() = val x: Any^ = "abc" - val y: Object @scala.annotation.retains(x) = ??? - val z: Object @scala.annotation.retains(x, caps.cap) = y: Object @annotation.retains(x) + val y: Object @scala.annotation.retains[x.type] = ??? + val z: Object @scala.annotation.retains[x.type | caps.cap.type] = y: Object @annotation.retains[x.type] diff --git a/tests/pos-custom-args/captures/capt2.scala b/tests/pos-custom-args/captures/capt2.scala index 45381bf602ed..3bfb1c70fbe8 100644 --- a/tests/pos-custom-args/captures/capt2.scala +++ b/tests/pos-custom-args/captures/capt2.scala @@ -1,18 +1,18 @@ import annotation.retains class C -type Cap = C @retains(caps.cap) +type Cap = C @retains[caps.cap.type] def test1() = val y: String^ = "" - def x: Object @retains(y) = y + def x: Object @retains[y.type] = y def test2() = val x: Cap = C() val y = () => { x; () } - def z: (() -> Unit) @retains(x) = y - z: (() -> Unit) @retains(x) - def z2: (() -> Unit) @retains(y) = y - z2: (() -> Unit) @retains(y) + def z: (() -> Unit) @retains[x.type] = y + z: (() -> Unit) @retains[x.type] + def z2: (() -> Unit) @retains[y.type] = y + z2: (() -> Unit) @retains[y.type] val p: () => String = () => "abc" val q: C^{p} = ??? val _ = p: (() ->{p} String) diff --git a/tests/pos-custom-args/captures/cc-expand.scala b/tests/pos-custom-args/captures/cc-expand.scala index 1bed7b1cf001..15529ad07ceb 100644 --- a/tests/pos-custom-args/captures/cc-expand.scala +++ b/tests/pos-custom-args/captures/cc-expand.scala @@ -5,18 +5,18 @@ object Test: class B class C class CTC - type CT = CTC @retains(caps.cap) + type CT = CTC @retains[caps.cap.type] def test(ct: CT, dt: CT) = def x0: A -> B^{ct} = ??? - def x1: A -> B @retains(ct) = ??? - def x2: A -> B -> C @retains(ct) = ??? - def x3: A -> () -> B -> C @retains(ct) = ??? + def x1: A -> B @retains[ct.type] = ??? + def x2: A -> B -> C @retains[ct.type] = ??? + def x3: A -> () -> B -> C @retains[ct.type] = ??? - def x4: (x: A @retains(ct)) -> B -> C = ??? + def x4: (x: A @retains[ct.type]) -> B -> C = ??? - def x5: A -> (x: B @retains(ct)) -> () -> C @retains(dt) = ??? - def x6: A -> (x: B @retains(ct)) -> (() -> C @retains(dt)) @retains(x, dt) = ??? - def x7: A -> (x: B @retains(ct)) -> (() -> C @retains(dt)) @retains(x) = ??? \ No newline at end of file + def x5: A -> (x: B @retains[ct.type]) -> () -> C @retains[dt.type] = ??? + def x6: A -> (x: B @retains[ct.type]) -> (() -> C @retains[dt.type]) @retains[x.type | dt.type] = ??? + def x7: A -> (x: B @retains[ct.type]) -> (() -> C @retains[dt.type]) @retains[x.type] = ??? \ No newline at end of file diff --git a/tests/pos-custom-args/captures/colltest.scala b/tests/pos-custom-args/captures/colltest.scala index eb2212f62b9b..e2f09297d571 100644 --- a/tests/pos-custom-args/captures/colltest.scala +++ b/tests/pos-custom-args/captures/colltest.scala @@ -1,3 +1,4 @@ +import language.experimental.captureChecking // Showing a problem with recursive references object CollectionStrawMan5 { @@ -17,14 +18,13 @@ object CollectionStrawMan5 { trait View[+A] extends Iterable[A] with IterableLike[A] case class Partition[A](val underlying: Iterable[A]^, p: A => Boolean) { - self: Partition[A]^{underlying, p} => class Partitioned(expected: Boolean) extends View[A]: - this: Partitioned^{self} => + this: Partitioned^{Partition.this} => def iterator: Iterator[A]^{this} = underlying.iterator.filter((x: A) => p(x) == expected) - val left: Partitioned^{self} = Partitioned(true) - val right: Partitioned^{self} = Partitioned(false) + val left: Partitioned^{Partition.this} = Partitioned(true) + val right: Partitioned^{Partition.this} = Partitioned(false) } } \ No newline at end of file diff --git a/tests/pos-custom-args/captures/correct-capture-variable-resolve.scala b/tests/pos-custom-args/captures/correct-capture-variable-resolve.scala new file mode 100644 index 000000000000..cc6ecf416c6d --- /dev/null +++ b/tests/pos-custom-args/captures/correct-capture-variable-resolve.scala @@ -0,0 +1,4 @@ +import language.experimental.captureChecking + +def f(x: AnyRef^, C: AnyRef^) = + def g[C^ <: {x}](y: AnyRef^{C}): AnyRef^{x} = y \ No newline at end of file diff --git a/tests/pos-custom-args/captures/i21868.scala b/tests/pos-custom-args/captures/i21868.scala index 5385902c2c53..560177c87d73 100644 --- a/tests/pos-custom-args/captures/i21868.scala +++ b/tests/pos-custom-args/captures/i21868.scala @@ -2,13 +2,13 @@ import language.experimental.captureChecking import caps.* trait AbstractWrong: - type C <: CapSet + type C^ <: CapSet // no longer an error, the lower bound becomes CapSet now def f(): Unit^{C} trait Abstract1: - type C^ + type C^ >: CapSet <: CapSet^ def f(): Unit^{C} -// class Abstract2: -// type C^ -// def f(): Unit^{C^} \ No newline at end of file +trait Abstract2: + type C^ <: {cap} + def f(): Unit^{C} \ No newline at end of file diff --git a/tests/pos-custom-args/captures/i23170.scala b/tests/pos-custom-args/captures/i23170.scala index 8e158b8e7839..886761a74e6e 100644 --- a/tests/pos-custom-args/captures/i23170.scala +++ b/tests/pos-custom-args/captures/i23170.scala @@ -5,4 +5,4 @@ trait A extension (a: A^{cap.rd}) def await = () -def awaitA[C <: {cap.rd}](a: A^{C}) = a.await \ No newline at end of file +def awaitA[C^ <: {cap.rd}](a: A^{C}) = a.await \ No newline at end of file diff --git a/tests/pos-custom-args/captures/list-encoding.scala b/tests/pos-custom-args/captures/list-encoding.scala index 7c593bb524e3..d427d1ae3f41 100644 --- a/tests/pos-custom-args/captures/list-encoding.scala +++ b/tests/pos-custom-args/captures/list-encoding.scala @@ -16,9 +16,9 @@ def cons[T](hd: T, tl: List[T]): List[T] = [C] => (op: Op[T, C]) => (s: C) => op(hd)(tl(op)(s)) def foo(c: Cap^) = - def f(x: String @retains(c), y: String @retains(c)) = + def f(x: String @retains[c.type], y: String @retains[c.type]) = cons(x, cons(y, nil)) - def g(x: String @retains(c), y: Any) = + def g(x: String @retains[c.type], y: Any) = cons(x, cons(y, nil)) - def h(x: String, y: Any @retains(c)) = + def h(x: String, y: Any @retains[c.type]) = cons(x, cons(y, nil)) diff --git a/tests/pos-custom-args/captures/try.scala b/tests/pos-custom-args/captures/try.scala index 05c41be69001..5faabecc411c 100644 --- a/tests/pos-custom-args/captures/try.scala +++ b/tests/pos-custom-args/captures/try.scala @@ -2,7 +2,7 @@ import annotation.retains import language.experimental.erasedDefinitions class CT[E <: Exception] -type CanThrow[E <: Exception] = CT[E] @retains(caps.cap) +type CanThrow[E <: Exception] = CT[E] @retains[caps.cap.type] infix type throws[R, E <: Exception] = (erased CanThrow[E]) ?-> R diff --git a/tests/pos/caps-universal.scala b/tests/pos/caps-universal.scala index 3451866ed8f3..fc9942c2a99a 100644 --- a/tests/pos/caps-universal.scala +++ b/tests/pos/caps-universal.scala @@ -3,7 +3,7 @@ import annotation.retains val id: Int -> Int = (x: Int) => x val foo: Int => Int = id -val bar: (Int -> Int) @retains(caps.cap) = foo +val bar: (Int -> Int) @retains[caps.cap.type] = foo diff --git a/tests/pos/i22257.scala b/tests/pos/i22257.scala index 8cd797529097..7f0dd75293f3 100644 --- a/tests/pos/i22257.scala +++ b/tests/pos/i22257.scala @@ -24,3 +24,11 @@ type Bound5 <: FP5 type Node6 = NodeK { type FBound <: Bound6 } type Bound6 <: FP6 type FP6 = Fixed[Node6] + +// type X^ +// type Y^ +// type Z >: X <: Y +// val Z + + +// type C <: \ No newline at end of file diff --git a/tests/run-custom-args/captures/colltest5/CollectionStrawManCC5_1.scala b/tests/run-custom-args/captures/colltest5/CollectionStrawManCC5_1.scala index 0d09e5c8cb40..ffb68c8d0d60 100644 --- a/tests/run-custom-args/captures/colltest5/CollectionStrawManCC5_1.scala +++ b/tests/run-custom-args/captures/colltest5/CollectionStrawManCC5_1.scala @@ -8,6 +8,8 @@ import annotation.tailrec import caps.cap import caps.unsafe.unsafeAssumeSeparate +import language.experimental.captureChecking + /** A strawman architecture for new collections. It contains some * example collection classes and methods with the intent to expose * some key issues. It would be good to compare this to other @@ -448,7 +450,6 @@ object CollectionStrawMan5 { } case class Filter[A](val underlying: Iterable[A]^, p: A => Boolean) extends View[A] { - this: Filter[A]^{underlying, p} => def iterator: Iterator[A]^{this} = underlying.iterator.filter(p) } @@ -466,37 +467,31 @@ object CollectionStrawMan5 { case _ => new Filter(underlying, pp) case class Partition[A](val underlying: Iterable[A]^, p: A => Boolean) { - self: Partition[A]^{underlying, p} => - class Partitioned(expected: Boolean) extends View[A]: - this: Partitioned^{self} => + this: Partitioned^{Partition.this} => def iterator: Iterator[A]^{this} = underlying.iterator.filter((x: A) => p(x) == expected) - val left: Partitioned^{self} = Partitioned(true) - val right: Partitioned^{self} = Partitioned(false) + val left: Partitioned^{this} = Partitioned(true) + val right: Partitioned^{this} = Partitioned(false) } case class Drop[A](underlying: Iterable[A]^, n: Int) extends View[A] { - this: Drop[A]^{underlying} => def iterator: Iterator[A]^{this} = underlying.iterator.drop(n) override def knownLength = if (underlying.knownLength >= 0) underlying.knownLength - n max 0 else -1 } case class Map[A, B](underlying: Iterable[A]^, f: A => B) extends View[B] { - this: Map[A, B]^{underlying, f} => def iterator: Iterator[B]^{this} = underlying.iterator.map(f) override def knownLength = underlying.knownLength } case class FlatMap[A, B](underlying: Iterable[A]^, f: A => IterableOnce[B]^) extends View[B] { - this: FlatMap[A, B]^{underlying, f} => def iterator: Iterator[B]^{this} = underlying.iterator.flatMap(f) } case class Concat[A](underlying: Iterable[A]^, other: IterableOnce[A]^) extends View[A] { - this: Concat[A]^{underlying, other} => def iterator: Iterator[A]^{this} = underlying.iterator ++ other override def knownLength = other match { case other: Iterable[_] if underlying.knownLength >= 0 && other.knownLength >= 0 => @@ -507,7 +502,6 @@ object CollectionStrawMan5 { } case class Zip[A, B](underlying: Iterable[A]^, other: IterableOnce[B]^) extends View[(A, B)] { - this: Zip[A, B]^{underlying, other} => def iterator: Iterator[(A, B)]^{this} = underlying.iterator.zip(other) override def knownLength = other match { case other: Iterable[_] if underlying.knownLength >= 0 && other.knownLength >= 0 => diff --git a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala index 6a867233b49b..fd0281c5fffc 100644 --- a/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala +++ b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala @@ -30,7 +30,6 @@ val experimentalDefinitionInLibrary = Set( "scala.annotation.retains", "scala.annotation.retainsByName", "scala.annotation.retainsCap", - "scala.annotation.retainsArg", "scala.Pure", "scala.caps.CapSet", "scala.caps.Capability",