diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 471a9953c4f0..df53031158e5 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -2261,9 +2261,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 145c61584fcc..a951f443a5bf 100644 --- a/compiler/src/dotty/tools/dotc/ast/untpd.scala +++ b/compiler/src/dotty/tools/dotc/ast/untpd.scala @@ -386,6 +386,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) @@ -528,10 +530,17 @@ 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 ref(defn.NothingType) + // TODO: choose a reduce direction + else refs.map(SingletonTypeTree).reduce[Tree]((a, b) => makeOrType(a, b)) + annot = New(AppliedTypeTree(annot, trefs :: Nil), Nil) + annot.putAttachment(RetainsAnnot, ()) + Annotated(parent, annot) // Capture set variable `[C^]` becomes: `[C >: CapSet <: CapSet^{cap}]` def makeCapsBound()(using Context): TypeBoundsTree = @@ -563,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/CaptureAnnotation.scala b/compiler/src/dotty/tools/dotc/cc/CaptureAnnotation.scala index 2be492ed6189..66384cfd508d 100644 --- a/compiler/src/dotty/tools/dotc/cc/CaptureAnnotation.scala +++ b/compiler/src/dotty/tools/dotc/cc/CaptureAnnotation.scala @@ -38,15 +38,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 cr: TermRef => ref(cr) - case cr: TermParamRef => untpd.Ident(cr.paramName).withType(cr) - case cr: ThisType => This(cr.cls) - case root(_) => ref(root.cap) - // 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 + val trefs = + if elems.isEmpty then defn.NothingType + else elems.reduce[Type]((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 908e3174bfce..bdb401fb6ce6 100644 --- a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala +++ b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala @@ -190,26 +190,6 @@ def ccState(using Context): CCState = extension (tree: Tree) - /** Map tree with CaptureRef type to its type, - * map CapSet^{refs} to the `refs` references, - * throw IllegalCaptureRef otherwise - */ - def toCaptureRefs(using Context): List[CaptureRef] = tree match - case ReachCapabilityApply(arg) => - arg.toCaptureRefs.map(_.reach) - case ReadOnlyCapabilityApply(arg) => - arg.toCaptureRefs.map(_.readOnly) - case CapsOfApply(arg) => - arg.toCaptureRefs - case _ => tree.tpe.dealiasKeepAnnots match - case ref: CaptureRef 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. */ @@ -217,11 +197,18 @@ extension (tree: Tree) tree.getAttachment(Captures) match case Some(refs) => refs case None => - val refs = CaptureSet(tree.retainedElems.flatMap(_.toCaptureRefs)*) - //.showing(i"toCaptureSet $tree --> $result", capt) + val refs = CaptureSet(tree.retainedSet.retainedElements*) tree.putAttachment(Captures, refs) refs + def retainedSet(using Context): Type = + tree match + case Apply(TypeApply(_, refs :: Nil), _) => refs.tpe + case _ => + if tree.symbol.maybeOwner == defn.RetainsCapAnnot + then root.cap + else NoType + /** The arguments of a @retains, @retainsCap or @retainsByName annotation */ def retainedElems(using Context): List[Tree] = tree match case Apply(_, Typed(SeqLiteral(elems, _), _) :: Nil) => @@ -233,6 +220,21 @@ extension (tree: Tree) extension (tp: Type) + def retainedElements(using Context): List[CaptureRef] = tp match + case ReachCapability(tp1) => + tp1.reach :: Nil + case ReadOnlyCapability(tp1) => + tp1.readOnly :: Nil + case tp: CaptureRef if tp.isTrackableRef => + tp :: Nil + case tp: TypeRef if tp.symbol.isType && tp.derivesFrom(defn.Caps_CapSet) => + tp :: Nil + case OrType(tp1, tp2) => + tp1.retainedElements ++ tp2.retainedElements + case _ => + if tp.isNothingType then Nil + else throw IllegalCaptureRef(tp) + /** Is this type a CaptureRef that can be tracked? * This is true for * - all ThisTypes and all TermParamRef, @@ -655,7 +657,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 @@ -773,7 +775,7 @@ 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) /** A typemap that follows aliases and keeps their transformed results if @@ -792,26 +794,18 @@ trait FollowAliasesMap(using Context) extends TypeMap: /** An extractor for `caps.reachCapability(ref)`, which is used to express a reach * capability as a tree in a @retains 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) - case _ => None +// 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) +// case _ => None /** An extractor for `caps.readOnlyCapability(ref)`, which is used to express a read-only * capability as a tree in a @retains annotation. */ -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 - -/** An extractor for `caps.capsOf[X]`, which is used to express a generic capture set - * as a tree in a @retains annotation. - */ -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 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 abstract class AnnotatedCapability(annotCls: Context ?=> ClassSymbol): def apply(tp: Type)(using Context): AnnotatedType = diff --git a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala index 4de1981553b6..2a3710a3f4b3 100644 --- a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala +++ b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala @@ -137,25 +137,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: CaptureRef => if !ref.isTrackableRef 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.retainedElements 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 6d52ad94613b..ad7bbfafe96a 100644 --- a/compiler/src/dotty/tools/dotc/cc/Setup.scala +++ b/compiler/src/dotty/tools/dotc/cc/Setup.scala @@ -810,7 +810,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 @@ -856,7 +856,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.isCap case _ => false case AnnotatedType(parent, _) => @@ -951,19 +951,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.toCaptureRefs - catch case ex: IllegalCaptureRef => - report.error(em"Illegal capture reference: ${ex.getMessage.nn}", refTree.srcPos) - Nil - for ref <- refs do + capt.println(i"checkWF post $parent ${ann.retainedSet} in $tpt") + try + val retainedRefs = ann.retainedSet.retainedElements.toArray + for i <- 0 until retainedRefs.length do + val ref = retainedRefs(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 = @@ -979,14 +973,15 @@ class Setup extends PreRecheck, SymTransformer, SetupAPI: val others = for - j <- 0 until retained.length if j != i - r <- retained(j).toCaptureRefs + j <- 0 until retainedRefs.length if j != i + r = retainedRefs(j) if !r.isRootCapability 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.nn}", 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 b88a3e6e986a..d680c246f8cb 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 @@ -998,9 +998,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") @@ -1093,7 +1090,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") diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala index 57bf870c6b64..9307e7d1662c 100644 --- a/compiler/src/dotty/tools/dotc/core/Flags.scala +++ b/compiler/src/dotty/tools/dotc/core/Flags.scala @@ -380,6 +380,8 @@ object Flags { /** Tracked modifier for class parameter / a class with some tracked parameters */ val (Tracked @ _, _, Dependent @ _) = newFlags(46, "tracked") + val (CaptureParam @ _, _, _) = newFlags(47, "capture-param") + // ------------ Flags following this one are not pickled ---------------------------------- /** Symbol is not a member of its owner */ @@ -449,7 +451,7 @@ object Flags { /** Flags representing source modifiers */ private val CommonSourceModifierFlags: FlagSet = - commonFlags(Private, Protected, Final, Case, Implicit, Given, Override, JavaStatic, Transparent, Erased) + commonFlags(Private, Protected, Final, Case, Implicit, Given, Override, JavaStatic, Transparent, Erased, CaptureParam) val TypeSourceModifierFlags: FlagSet = CommonSourceModifierFlags.toTypeFlags | Abstract | Sealed | Opaque | Open @@ -469,7 +471,7 @@ object Flags { val FromStartFlags: FlagSet = commonFlags( Module, Package, Deferred, Method, Case, Enum, Param, ParamAccessor, Scala2SpecialFlags, MutableOrOpen, Opaque, Touched, JavaStatic, - OuterOrCovariant, LabelOrContravariant, CaseAccessor, Tracked, + OuterOrCovariant, LabelOrContravariant, CaseAccessor, Tracked, CaptureParam, Extension, NonMember, Implicit, Given, Permanent, Synthetic, Exported, SuperParamAliasOrScala2x, Inline, Macro, ConstructorProxy, Invisible) diff --git a/compiler/src/dotty/tools/dotc/core/Mode.scala b/compiler/src/dotty/tools/dotc/core/Mode.scala index 6fd76e37977d..571a786e9106 100644 --- a/compiler/src/dotty/tools/dotc/core/Mode.scala +++ b/compiler/src/dotty/tools/dotc/core/Mode.scala @@ -91,6 +91,14 @@ object Mode { */ val ImplicitExploration: Mode = newMode(12, "ImplicitExploration") + /** We are currently inside a capture set. + * A term name could be a capture variable, so we need to + * check that it is valid to use as type name. + * Since this mode is only used during annotation typing, + * we can reuse the value of `ImplicitExploration` to save bits. + */ + val InCaptureSet: Mode = ImplicitExploration + /** We are currently unpickling Scala2 info */ val Scala2Unpickling: Mode = newMode(13, "Scala2Unpickling") diff --git a/compiler/src/dotty/tools/dotc/core/NamerOps.scala b/compiler/src/dotty/tools/dotc/core/NamerOps.scala index dbdb46aba334..7d0b22421e18 100644 --- a/compiler/src/dotty/tools/dotc/core/NamerOps.scala +++ b/compiler/src/dotty/tools/dotc/core/NamerOps.scala @@ -317,4 +317,17 @@ object NamerOps: ann.tree match 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. + * + * @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 | StableRealizable | Synthetic + val dummy = newSymbol(param.owner, name, flags, param.typeRef) + typr.println(i"Adding dummy term symbol $dummy for $param, flags = $flags") + ctx.enter(dummy) + end NamerOps diff --git a/compiler/src/dotty/tools/dotc/core/StdNames.scala b/compiler/src/dotty/tools/dotc/core/StdNames.scala index c33c795571e6..b97df6a49248 100644 --- a/compiler/src/dotty/tools/dotc/core/StdNames.scala +++ b/compiler/src/dotty/tools/dotc/core/StdNames.scala @@ -445,7 +445,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" diff --git a/compiler/src/dotty/tools/dotc/core/SymUtils.scala b/compiler/src/dotty/tools/dotc/core/SymUtils.scala index 1b83014e5735..a749af714c85 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.is(Synthetic) && self.is(CaptureParam) + /** 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/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index df7700c73a17..3fb0eb290ad9 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -748,7 +748,8 @@ object Types extends TypeUtils { case tp: ClassInfo => tp.appliedRef case _ => widenIfUnstable } - findMember(name, pre, required, excluded) + val excluded1 = if ctx.mode.is(Mode.InCaptureSet) then excluded else excluded | CaptureParam + findMember(name, pre, required, excluded1) } /** The implicit members with given name. If there are none and the denotation diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index c24dbce1b6ac..c80b45670e09 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -1601,7 +1601,7 @@ object Parsers { } /** CaptureRef ::= { SimpleRef `.` } SimpleRef [`*`] [`.` rd] - * | [ { SimpleRef `.` } SimpleRef `.` ] id `^` + * | [ { SimpleRef `.` } SimpleRef `.` ] id */ def captureRef(): Tree = @@ -1620,12 +1620,6 @@ object Parsers { in.nextToken() derived(reachRef, nme.CC_READONLY) else reachRef - else if isIdent(nme.UPARROW) then - in.nextToken() - atSpan(startOffset(ref)): - convertToTypeId(ref) match - case ref: RefTree => makeCapsOf(ref) - case ref => ref else ref recur(simpleRef()) diff --git a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala index 0dcb06ae8c87..3b61e9a8f426 100644 --- a/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala +++ b/compiler/src/dotty/tools/dotc/printing/PlainPrinter.scala @@ -173,10 +173,6 @@ class PlainPrinter(_ctx: Context) extends Printer { private def toTextRetainedElem[T <: Untyped](ref: Tree[T]): Text = ref match case ref: RefTree[?] if ref.typeOpt.exists => toTextCaptureRef(ref.typeOpt) - 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 = @@ -277,11 +273,12 @@ class PlainPrinter(_ctx: Context) extends Printer { else toTextCaptureSet(refs) toTextCapturing(parent, refsText, boxText) - case tp @ RetainingType(parent, refs) => + case tp @ RetainingType(parent, refsType) => + val refs = refsType.retainedElements if Feature.ccEnabledSomewhere then val refsText = refs match - case ref :: Nil if ref.symbol == defn.captureRoot => rootSetText - case _ => toTextRetainedElems(refs) + case (ref: TermRef) :: Nil if ref.symbol == defn.captureRoot => rootSetText + case _ => toTextRetainedElems(refs.map(r => ast.tpd.TypeTree(r))) toTextCapturing(parent, refsText, "") ~ Str("R").provided(printDebug) else toText(parent) case tp: PreviousErrorType if ctx.settings.XprintTypes.value => diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index df74e102f693..646d30695e85 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -348,6 +348,8 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => unusable(ConstructorProxyNotValue(_)) else if tree.symbol.isContextBoundCompanion then unusable(ContextBoundCompanionNotValue(_)) + else if tree.symbol.isDummyCaptureParam then + throw new Exception(s"Dummy capture param ${tree.symbol} should not be used as a value") else tree diff --git a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala index 90262bc5da85..7c1ced3b2241 100644 --- a/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala +++ b/compiler/src/dotty/tools/dotc/transform/TreeChecker.scala @@ -387,7 +387,9 @@ object TreeChecker { } def isSymWithoutDef(sym: Symbol)(using Context): Boolean = - sym.is(ConstructorProxy) || sym.isContextBoundCompanion + sym.is(ConstructorProxy) + || sym.isContextBoundCompanion + || sym.isDummyCaptureParam /** 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 71fc250d0710..ff1bc5ede915 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -36,6 +36,7 @@ import annotation.threadUnsafe import scala.util.control.NonFatal import dotty.tools.dotc.inlines.Inlines +import dotty.tools.dotc.cc.isRetains object Applications { import tpd.* diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 89dc4cf53472..958aeefb3330 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -1132,6 +1132,9 @@ class Namer { typer: Typer => ensureUpToDate(sym.typeRef, dummyInfo1) if (dummyInfo2 `ne` dummyInfo1) ensureUpToDate(sym.typeRef, dummyInfo2) + if sym.info.derivesFrom(defn.Caps_CapSet) then + addDummyTermCaptureParam(sym)(using ictx) + sym.info end typeSig } diff --git a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala index 17e475e50a49..18a22f511850 100644 --- a/compiler/src/dotty/tools/dotc/typer/RefChecks.scala +++ b/compiler/src/dotty/tools/dotc/typer/RefChecks.scala @@ -473,8 +473,8 @@ 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)) { + // 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) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 4d16a342f484..4c5f08f285db 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -162,7 +162,8 @@ trait TypeAssigner { // if this fails. ctx.javaFindMember(name, pre, lookInCompanion = false) else - qualType.findMember(name, pre) + val excluded = if ctx.mode.is(Mode.InCaptureSet) then EmptyFlags else CaptureParam + qualType.findMember(name, pre, excluded = excluded) if reallyExists(mbr) && NamedType.validPrefix(qualType) then qualType.select(name, mbr) else if qualType.isErroneous || name.toTermName == nme.ERROR then UnspecifiedErrorType diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 6b7b840e7606..2313a7316355 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -626,8 +626,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer val saved2 = foundUnderScala2 unimported = Set.empty foundUnderScala2 = NoType + val excluded = if ctx.mode.is(Mode.InCaptureSet) then EmptyFlags else CaptureParam try - val found = findRef(name, pt, EmptyFlags, EmptyFlags, tree.srcPos) + val found = findRef(name, pt, EmptyFlags, excluded, tree.srcPos) if foundUnderScala2.exists && !(foundUnderScala2 =:= found) then report.migrationWarning( em"""Name resolution will change. @@ -2526,8 +2527,11 @@ 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.is(Flags.CaptureParam) then + // println(s"typedSingletonTypeTree: $ref1 -> ${ref1.tpe.widen}") + return Ident(ref1.tpe.widen.asInstanceOf[TypeRef]).withSpan(tree.span) checkStable(ref1.tpe, tree.srcPos, "singleton type") assignType(cpy.SingletonTypeTree(tree)(ref1), ref1) } @@ -3365,7 +3369,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 @@ -4477,15 +4484,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 909adc13a1c2..b425d075680f 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 -Ycc. * - * 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 7f8b184c1c95..2ebc270b340e 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/capset-bound.scala b/tests/neg-custom-args/captures/capset-bound.scala index c00f61240dea..80ee3804776f 100644 --- a/tests/neg-custom-args/captures/capset-bound.scala +++ b/tests/neg-custom-args/captures/capset-bound.scala @@ -5,7 +5,7 @@ class IO case class File(io: IO^) def test(io1: IO^, io2: IO^) = - def f[C >: CapSet^{io1} <: CapSet^](file: File^{C^}) = ??? + def f[C >: CapSet^{io1} <: CapSet^](file: File^{C}) = ??? val f1: File^{io1} = ??? val f2: File^{io2} = ??? val f3: File^{io1, io2} = ??? diff --git a/tests/neg-custom-args/captures/capset-bound2.scala b/tests/neg-custom-args/captures/capset-bound2.scala index 679606f0e43c..4cee6b244de7 100644 --- a/tests/neg-custom-args/captures/capset-bound2.scala +++ b/tests/neg-custom-args/captures/capset-bound2.scala @@ -2,7 +2,7 @@ import caps.* class IO -def f[C^](io: IO^{C^}) = ??? +def f[C^](io: IO^{C}) = ??? def test = f[CapSet](???) @@ -10,4 +10,3 @@ def test = f[CapSet^](???) f[Nothing](???) // error f[String](???) // error - \ No newline at end of file diff --git a/tests/neg-custom-args/captures/capset-members.scala b/tests/neg-custom-args/captures/capset-members.scala index 540216852a43..44720b68ff84 100644 --- a/tests/neg-custom-args/captures/capset-members.scala +++ b/tests/neg-custom-args/captures/capset-members.scala @@ -3,7 +3,7 @@ import caps.* trait Abstract[X^]: type C >: X <: CapSet^ // Don't test the return type using Unit, because it is a pure type. - def boom(): AnyRef^{C^} + def boom(): AnyRef^{C} class Concrete extends Abstract[CapSet^{}]: type C = CapSet^{} @@ -27,4 +27,3 @@ class Concrete5(a: AnyRef^, b: AnyRef^) extends Abstract[CapSet^{a}]: class Concrete6(a: AnyRef^, b: AnyRef^) extends Abstract[CapSet^{a}]: def boom(): AnyRef^{b} = b // error - \ 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 80ee1aba84e1..fd81ca2c9a74 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..704d6768c194 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[x7 + x7] = ??? // 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 804e18072752..8c5d504ec07a 100644 --- a/tests/neg-custom-args/captures/capt1.check +++ b/tests/neg-custom-args/captures/capt1.check @@ -44,7 +44,7 @@ | reference (x : C^) is not included in the allowed capture set {} | of an enclosing function literal with expected type () -> box C^ -- 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 d59305ae0cb8..d9288a062ded 100644 --- a/tests/neg-custom-args/captures/capture-parameters.scala +++ b/tests/neg-custom-args/captures/capture-parameters.scala @@ -2,8 +2,7 @@ import caps.* class C -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 - \ No newline at end of file +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/capture-poly.scala b/tests/neg-custom-args/captures/capture-poly.scala index 88989b418726..9276eab0342f 100644 --- a/tests/neg-custom-args/captures/capture-poly.scala +++ b/tests/neg-custom-args/captures/capture-poly.scala @@ -5,8 +5,8 @@ trait Foo extends Capability trait CaptureSet: type C >: CapSet <: CapSet^ -def capturePoly[C^](a: Foo^{C^}): Foo^{C^} = a -def capturePoly2(c: CaptureSet)(a: Foo^{c.C^}): Foo^{c.C^} = a +def capturePoly[C^](a: Foo^{C}): Foo^{C} = a +def capturePoly2(c: CaptureSet)(a: Foo^{c.C}): Foo^{c.C} = a def test = val x: Foo^ = ??? @@ -15,8 +15,8 @@ def test = object X extends CaptureSet: type C = CapSet^{x} - val z1: Foo^{X.C^} = x - val z2: Foo^{X.C^} = y // error + val z1: Foo^{X.C} = x + val z2: Foo^{X.C} = y // error val z3: Foo^{x} = capturePoly(x) val z4: Foo^{x} = capturePoly(y) // error diff --git a/tests/neg-custom-args/captures/capture-vars-subtyping.scala b/tests/neg-custom-args/captures/capture-vars-subtyping.scala index 1986a0aa33fc..c0356bb0873f 100644 --- a/tests/neg-custom-args/captures/capture-vars-subtyping.scala +++ b/tests/neg-custom-args/captures/capture-vars-subtyping.scala @@ -3,32 +3,32 @@ import caps.* def test[C^] = val a: C = ??? - val b: CapSet^{C^} = a + val b: CapSet^{C} = a val c: C = b - val d: CapSet^{C^, c} = a + val d: CapSet^{C, c} = a // TODO: make "CapSet-ness" of type variables somehow contagious? // Then we don't have to spell out the bounds explicitly... def testTrans[C^, D >: CapSet <: C, E >: CapSet <: D, F >: C <: CapSet^] = val d1: D = ??? - val d2: CapSet^{D^} = d1 + val d2: CapSet^{D} = d1 val d3: D = d2 val e1: E = ??? - val e2: CapSet^{E^} = e1 + val e2: CapSet^{E} = e1 val e3: E = e2 val d4: D = e1 val c1: C = d1 val c2: C = e1 val f1: F = c1 - val d_e_f1: CapSet^{D^,E^,F^} = d1 - val d_e_f2: CapSet^{D^,E^,F^} = e1 - val d_e_f3: CapSet^{D^,E^,F^} = f1 + val d_e_f1: CapSet^{D,E,F} = d1 + val d_e_f2: CapSet^{D,E,F} = e1 + val d_e_f3: CapSet^{D,E,F} = f1 val f2: F = d_e_f1 val c3: C = d_e_f1 // error val c4: C = f1 // error val e4: E = f1 // error val e5: E = d1 // error - val c5: CapSet^{C^} = e1 + val c5: CapSet^{C} = e1 trait A[+T] @@ -37,12 +37,12 @@ trait B[-C] def testCong[C^, D^] = val a: A[C] = ??? - val b: A[CapSet^{C^}] = a - val c: A[CapSet^{D^}] = a // error - val d: A[CapSet^{C^,D^}] = a + val b: A[CapSet^{C}] = a + val c: A[CapSet^{D}] = a // error + val d: A[CapSet^{C,D}] = a val e: A[C] = d // error val f: B[C] = ??? - val g: B[CapSet^{C^}] = f + val g: B[CapSet^{C}] = f val h: B[C] = g - val i: B[CapSet^{C^,D^}] = h // error + val i: B[CapSet^{C,D}] = h // error val j: B[C] = i diff --git a/tests/neg-custom-args/captures/capture-vars-subtyping2.scala b/tests/neg-custom-args/captures/capture-vars-subtyping2.scala index 205451ee41ed..0a3d776227cb 100644 --- a/tests/neg-custom-args/captures/capture-vars-subtyping2.scala +++ b/tests/neg-custom-args/captures/capture-vars-subtyping2.scala @@ -10,32 +10,32 @@ trait BoundsTest: def testTransMixed[A^, B >: CapSet <: A, - C >: CapSet <: CapSet^{B^}, + C >: CapSet <: CapSet^{B}, D >: CapSet <: C, - E >: CapSet <: CapSet^{D^}, - F >: CapSet <: CapSet^{A^,b}, - X >: CapSet <: CapSet^{F^,D^}, - Y >: CapSet^{F^} <: CapSet^{F^,A^,b}, - Z >: CapSet^{b} <: CapSet^{b,Y^}] = + E >: CapSet <: CapSet^{D}, + F >: CapSet <: CapSet^{A,b}, + X >: CapSet <: CapSet^{F,D}, + Y >: CapSet^{F} <: CapSet^{F,A,b}, + Z >: CapSet^{b} <: CapSet^{b,Y}] = val e: E = ??? - val e2: CapSet^{E^} = e + val e2: CapSet^{E} = e val ed: D = e - val ed2: CapSet^{D^} = e + val ed2: CapSet^{D} = e val ec: C = e - val ec2: CapSet^{C^} = e + val ec2: CapSet^{C} = e val eb: B = e - val eb2: CapSet^{B^} = e + val eb2: CapSet^{B} = e val ea: A = e - val ea2: CapSet^{A^} = e + val ea2: CapSet^{A} = e val ex: X = e // error - val ex2: CapSet^{X^} = e // error + val ex2: CapSet^{X} = e // error val f: F = ??? - val f2: CapSet^{F^} = f + val f2: CapSet^{F} = f val y: Y = f - val y2: CapSet^{Y^} = f + val y2: CapSet^{Y} = f val cb: CapSet^{b} = ??? val z: Z = cb - val z2: CapSet^{Z^} = cb + val z2: CapSet^{Z} = cb def callTransMixed = val x, y, z: Bar^ = ??? diff --git a/tests/neg-custom-args/captures/cc-poly-1.scala b/tests/neg-custom-args/captures/cc-poly-1.scala index 580b124bc8f3..b205b9b25246 100644 --- a/tests/neg-custom-args/captures/cc-poly-1.scala +++ b/tests/neg-custom-args/captures/cc-poly-1.scala @@ -6,7 +6,7 @@ object Test: class C extends Capability class D - def f[X^](x: D^{X^}): D^{X^} = x + def f[X^](x: D^{X}): D^{X} = x def test(c1: C, c2: C) = f[Any](D()) // error diff --git a/tests/neg-custom-args/captures/cc-poly-2.scala b/tests/neg-custom-args/captures/cc-poly-2.scala index c9249ba59437..8fb590f4f769 100644 --- a/tests/neg-custom-args/captures/cc-poly-2.scala +++ b/tests/neg-custom-args/captures/cc-poly-2.scala @@ -6,7 +6,7 @@ object Test: class C extends Capability class D - def f[X^](x: D^{X^}): D^{X^} = x + def f[X^](x: D^{X}): D^{X} = x def test(c1: C, c2: C) = val d: D^ = D() diff --git a/tests/neg-custom-args/captures/cc-poly-source.scala b/tests/neg-custom-args/captures/cc-poly-source.scala index e08ea36a6fc9..ec98c40a4fa9 100644 --- a/tests/neg-custom-args/captures/cc-poly-source.scala +++ b/tests/neg-custom-args/captures/cc-poly-source.scala @@ -10,11 +10,11 @@ import caps.use class Listener class Source[X^]: - private var listeners: Set[Listener^{X^}] = Set.empty - def register(x: Listener^{X^}): Unit = + private var listeners: Set[Listener^{X}] = Set.empty + def register(x: Listener^{X}): Unit = listeners += x - def allListeners: Set[Listener^{X^}] = listeners + def allListeners: Set[Listener^{X}] = listeners def test1(lbl1: Label^, lbl2: Label^) = val src = Source[CapSet^{lbl1, lbl2}] diff --git a/tests/neg-custom-args/captures/cc-this3.check b/tests/neg-custom-args/captures/cc-this3.check index d57471c6872e..904710574180 100644 --- a/tests/neg-custom-args/captures/cc-this3.check +++ b/tests/neg-custom-args/captures/cc-this3.check @@ -1,12 +1,12 @@ --- [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 | | 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/i21313.scala b/tests/neg-custom-args/captures/i21313.scala index 01bedb10aefd..4b6d16c4da88 100644 --- a/tests/neg-custom-args/captures/i21313.scala +++ b/tests/neg-custom-args/captures/i21313.scala @@ -6,7 +6,7 @@ trait Async: def foo(x: Async) = x.await(???) // error trait Source[+T, Cap^]: - final def await(using ac: Async^{Cap^}) = ac.await[T, Cap](this) // Contains[Cap, ac] is assured because {ac} <: Cap. + final def await(using ac: Async^{Cap}) = ac.await[T, Cap](this) // Contains[Cap, ac] is assured because {ac} <: Cap. def test(using ac1: Async^, ac2: Async^, x: String) = val src1 = new Source[Int, CapSet^{ac1}] {} diff --git a/tests/neg-custom-args/captures/i21347.scala b/tests/neg-custom-args/captures/i21347.scala index 54fe859caedd..2e37511f053c 100644 --- a/tests/neg-custom-args/captures/i21347.scala +++ b/tests/neg-custom-args/captures/i21347.scala @@ -1,6 +1,6 @@ import language.experimental.captureChecking -def runOps[C^](ops: List[() ->{C^} Unit]): Unit = +def runOps[C^](ops: List[() ->{C} Unit]): Unit = ops.foreach: op => // error op() diff --git a/tests/neg-custom-args/captures/i21868.scala b/tests/neg-custom-args/captures/i21868.scala index 876b68ac90a4..de6a9b64b78b 100644 --- a/tests/neg-custom-args/captures/i21868.scala +++ b/tests/neg-custom-args/captures/i21868.scala @@ -2,11 +2,11 @@ import caps.* trait AbstractWrong: type C <: CapSet - def f(): Unit^{C^} // error + def f(): Unit^{C} // error trait Abstract1: type C >: CapSet <: CapSet^ - def f(): Unit^{C^} + def f(): Unit^{C} // class Abstract2: // type C^ diff --git a/tests/neg-custom-args/captures/i21868b.scala b/tests/neg-custom-args/captures/i21868b.scala index 70f4e9c9d59c..6bc79cd684f0 100644 --- a/tests/neg-custom-args/captures/i21868b.scala +++ b/tests/neg-custom-args/captures/i21868b.scala @@ -1,3 +1,4 @@ +import language.experimental.captureChecking import language.experimental.modularity import caps.* @@ -7,7 +8,7 @@ class File trait Abstract: type C >: CapSet <: CapSet^ - def f(file: File^{C^}): Unit + def f(file: File^{C}): Unit class Concrete1 extends Abstract: type C = CapSet @@ -23,7 +24,7 @@ class Concrete3(io: IO^) extends Abstract: trait Abstract2(tracked val io: IO^): type C >: CapSet <: CapSet^{io} - def f(file: File^{C^}): Unit + def f(file: File^{C}): Unit class Concrete4(io: IO^) extends Abstract2(io): type C = CapSet @@ -35,7 +36,7 @@ class Concrete5(io1: IO^, io2: IO^) extends Abstract2(io1): trait Abstract3[X^]: type C >: CapSet <: X - def f(file: File^{C^}): Unit + def f(file: File^{C}): Unit class Concrete6(io: IO^) extends Abstract3[CapSet^{io}]: type C = CapSet diff --git a/tests/neg-custom-args/captures/i22005.scala b/tests/neg-custom-args/captures/i22005.scala index 689246d6f835..6737e2c8cb6a 100644 --- a/tests/neg-custom-args/captures/i22005.scala +++ b/tests/neg-custom-args/captures/i22005.scala @@ -5,5 +5,5 @@ class IO class File(io: IO^) class Handler[C^]: - def f(file: File^): File^{C^} = file // error - def g(@consume file: File^{C^}): File^ = file // ok + def f(file: File^): File^{C} = file // error + def g(@consume file: File^{C}): File^ = file // ok 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/polyCaptures.check b/tests/neg-custom-args/captures/polyCaptures.check index 8173828b7bc8..08ebaf1c63ee 100644 --- a/tests/neg-custom-args/captures/polyCaptures.check +++ b/tests/neg-custom-args/captures/polyCaptures.check @@ -1,8 +1,8 @@ -- Error: tests/neg-custom-args/captures/polyCaptures.scala:4:22 ------------------------------------------------------- -4 |val runOpsCheck: [C^] -> (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error +4 |val runOpsCheck: [C^] -> (ops: List[() ->{C} Unit]) ->{C} Unit = runOps // error | ^ | Implementation restriction: polymorphic function types cannot wrap function types that have capture sets -- Error: tests/neg-custom-args/captures/polyCaptures.scala:5:23 ------------------------------------------------------- -5 |val runOpsCheck2: [C^] => (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error +5 |val runOpsCheck2: [C^] => (ops: List[() ->{C} Unit]) ->{C} Unit = runOps // error | ^ | Implementation restriction: polymorphic function types cannot wrap function types that have capture sets diff --git a/tests/neg-custom-args/captures/polyCaptures.scala b/tests/neg-custom-args/captures/polyCaptures.scala index 776af95e5dcf..eb8e50f0b997 100644 --- a/tests/neg-custom-args/captures/polyCaptures.scala +++ b/tests/neg-custom-args/captures/polyCaptures.scala @@ -1,7 +1,7 @@ class Box[X](val elem: X) -val runOps = [C^] => (b: Box[() ->{C^} Unit]) => b.elem() -val runOpsCheck: [C^] -> (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error -val runOpsCheck2: [C^] => (ops: List[() ->{C^} Unit]) ->{C^} Unit = runOps // error +val runOps = [C^] => (b: Box[() ->{C} Unit]) => b.elem() +val runOpsCheck: [C^] -> (ops: List[() ->{C} Unit]) ->{C} Unit = runOps // error +val runOpsCheck2: [C^] => (ops: List[() ->{C} Unit]) ->{C} Unit = runOps // error diff --git a/tests/neg-custom-args/captures/try.scala b/tests/neg-custom-args/captures/try.scala index a85a18f69caa..ccdcaf88879e 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/neg-custom-args/captures/use-capset.check b/tests/neg-custom-args/captures/use-capset.check index 4897698e336d..70b63e87d792 100644 --- a/tests/neg-custom-args/captures/use-capset.check +++ b/tests/neg-custom-args/captures/use-capset.check @@ -1,8 +1,8 @@ --- Error: tests/neg-custom-args/captures/use-capset.scala:5:50 --------------------------------------------------------- -5 |private def g[C^] = (xs: List[Object^{C^}]) => xs.head // error - | ^^^^^^^ - | Capture set parameter C leaks into capture scope of method g. - | To allow this, the type C should be declared with a @use annotation +-- Error: tests/neg-custom-args/captures/use-capset.scala:5:49 --------------------------------------------------------- +5 |private def g[C^] = (xs: List[Object^{C}]) => xs.head // error + | ^^^^^^^ + | Capture set parameter C leaks into capture scope of method g. + | To allow this, the type C should be declared with a @use annotation -- [E007] Type Mismatch Error: tests/neg-custom-args/captures/use-capset.scala:11:22 ----------------------------------- 11 | val _: () -> Unit = h // error: should be ->{io} | ^ diff --git a/tests/neg-custom-args/captures/use-capset.scala b/tests/neg-custom-args/captures/use-capset.scala index 74288d616396..4f2c239247e6 100644 --- a/tests/neg-custom-args/captures/use-capset.scala +++ b/tests/neg-custom-args/captures/use-capset.scala @@ -1,10 +1,10 @@ import caps.{use, CapSet} -def f[C^](@use xs: List[Object^{C^}]): Unit = ??? +def f[C^](@use xs: List[Object^{C}]): Unit = ??? -private def g[C^] = (xs: List[Object^{C^}]) => xs.head // error +private def g[C^] = (xs: List[Object^{C}]) => xs.head // error -private def g2[@use C^] = (xs: List[Object^{C^}]) => xs.head // ok +private def g2[@use C^] = (xs: List[Object^{C}]) => xs.head // ok def test(io: Object^)(@use xs: List[Object^{io}]): Unit = val h = () => f(xs) 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/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/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/cc-poly-1.scala b/tests/pos-custom-args/captures/cc-poly-1.scala index ed32d94f7a99..e423d94d4000 100644 --- a/tests/pos-custom-args/captures/cc-poly-1.scala +++ b/tests/pos-custom-args/captures/cc-poly-1.scala @@ -7,9 +7,9 @@ import caps.{CapSet, Capability} class C extends Capability class D - def f[X^](x: D^{X^}): D^{X^} = x - def g[X^](x: D^{X^}, y: D^{X^}): D^{X^} = x - def h[X^](): D^{X^} = ??? + def f[X^](x: D^{X}): D^{X} = x + def g[X^](x: D^{X}, y: D^{X}): D^{X} = x + def h[X^](): D^{X} = ??? def test(c1: C, c2: C) = val d: D^{c1, c2} = D() diff --git a/tests/pos-custom-args/captures/cc-poly-source-capability.scala b/tests/pos-custom-args/captures/cc-poly-source-capability.scala index 6f987658923c..1208649193af 100644 --- a/tests/pos-custom-args/captures/cc-poly-source-capability.scala +++ b/tests/pos-custom-args/captures/cc-poly-source-capability.scala @@ -12,11 +12,11 @@ import caps.use class Listener class Source[X^]: - private var listeners: Set[Listener^{X^}] = Set.empty - def register(x: Listener^{X^}): Unit = + private var listeners: Set[Listener^{X}] = Set.empty + def register(x: Listener^{X}): Unit = listeners += x - def allListeners: Set[Listener^{X^}] = listeners + def allListeners: Set[Listener^{X}] = listeners def test1(async1: Async, @use others: List[Async]) = val src = Source[CapSet^{async1, others*}] diff --git a/tests/pos-custom-args/captures/cc-poly-varargs.scala b/tests/pos-custom-args/captures/cc-poly-varargs.scala index 8bd0dc89bc7a..13e4b276df5a 100644 --- a/tests/pos-custom-args/captures/cc-poly-varargs.scala +++ b/tests/pos-custom-args/captures/cc-poly-varargs.scala @@ -1,13 +1,13 @@ abstract class Source[+T, Cap^] extension[T, Cap^](src: Source[T, Cap]^) - def transformValuesWith[U](f: (T -> U)^{Cap^}): Source[U, Cap]^{src, f} = ??? + def transformValuesWith[U](f: (T -> U)^{Cap}): Source[U, Cap]^{src, f} = ??? -def race[T, Cap^](sources: Source[T, Cap]^{Cap^}*): Source[T, Cap]^{Cap^} = ??? +def race[T, Cap^](sources: Source[T, Cap]^{Cap}*): Source[T, Cap]^{Cap} = ??? def either[T1, T2, Cap^]( - src1: Source[T1, Cap]^{Cap^}, - src2: Source[T2, Cap]^{Cap^}): Source[Either[T1, T2], Cap]^{Cap^} = + src1: Source[T1, Cap]^{Cap}, + src2: Source[T2, Cap]^{Cap}): Source[Either[T1, T2], Cap]^{Cap} = val left = src1.transformValuesWith(Left(_)) val right = src2.transformValuesWith(Right(_)) race(left, right) diff --git a/tests/pos-custom-args/captures/gears-problem-poly.scala b/tests/pos-custom-args/captures/gears-problem-poly.scala index fdbcf37a35a6..f7632bce4124 100644 --- a/tests/pos-custom-args/captures/gears-problem-poly.scala +++ b/tests/pos-custom-args/captures/gears-problem-poly.scala @@ -7,8 +7,8 @@ trait Future[+T]: trait Channel[+T]: def read(): Ok[T] -class Collector[T, C^](val futures: Seq[Future[T]^{C^}]): - val results: Channel[Future[T]^{C^}] = ??? +class Collector[T, C^](val futures: Seq[Future[T]^{C}]): + val results: Channel[Future[T]^{C}] = ??? end Collector class Result[+T, +E]: @@ -17,10 +17,10 @@ class Result[+T, +E]: case class Err[+E](e: E) extends Result[Nothing, E] case class Ok[+T](x: T) extends Result[T, Nothing] -extension [T, C^](@use fs: Seq[Future[T]^{C^}]) +extension [T, C^](@use fs: Seq[Future[T]^{C}]) def awaitAllPoly = val collector = Collector(fs) - val fut: Future[T]^{C^} = collector.results.read().get + val fut: Future[T]^{C} = collector.results.read().get extension [T](@use fs: Seq[Future[T]^]) def awaitAll = fs.awaitAllPoly diff --git a/tests/pos-custom-args/captures/i21313.scala b/tests/pos-custom-args/captures/i21313.scala index b388b6487cb5..e55bf9c7ce62 100644 --- a/tests/pos-custom-args/captures/i21313.scala +++ b/tests/pos-custom-args/captures/i21313.scala @@ -3,17 +3,17 @@ import caps.CapSet trait Async: def await[T, Cap^](using caps.Contains[Cap, this.type])(src: Source[T, Cap]^): T = val x: Async^{this} = ??? - val y: Async^{Cap^} = x + val y: Async^{Cap} = x val ac: Async^ = ??? def f(using caps.Contains[Cap, ac.type]) = val x2: Async^{this} = ??? - val y2: Async^{Cap^} = x2 + val y2: Async^{Cap} = x2 val x3: Async^{ac} = ??? - val y3: Async^{Cap^} = x3 + val y3: Async^{Cap} = x3 ??? trait Source[+T, Cap^]: - final def await(using ac: Async^{Cap^}) = ac.await[T, Cap](this) // Contains[Cap, ac] is assured because {ac} <: Cap. + final def await(using ac: Async^{Cap}) = ac.await[T, Cap](this) // Contains[Cap, ac] is assured because {ac} <: Cap. def test(using ac1: Async^, ac2: Async^, x: String) = val src1 = new Source[Int, CapSet^{ac1}] {} diff --git a/tests/pos-custom-args/captures/i21347.scala b/tests/pos-custom-args/captures/i21347.scala index a965b7e4f26b..9dbb8b154cfb 100644 --- a/tests/pos-custom-args/captures/i21347.scala +++ b/tests/pos-custom-args/captures/i21347.scala @@ -4,7 +4,7 @@ import language.experimental.captureChecking class Box[Cap^] {} -def run[Cap^](f: Box[Cap]^{Cap^} => Unit): Box[Cap]^{Cap^} = ??? +def run[Cap^](f: Box[Cap]^{Cap} => Unit): Box[Cap]^{Cap} = ??? def main() = val b = run(_ => ()) diff --git a/tests/pos-custom-args/captures/i21507.scala b/tests/pos-custom-args/captures/i21507.scala index bb80dafb3b45..4267795d3a41 100644 --- a/tests/pos-custom-args/captures/i21507.scala +++ b/tests/pos-custom-args/captures/i21507.scala @@ -1,10 +1,10 @@ import language.experimental.captureChecking trait Box[Cap^]: - def store(f: (() -> Unit)^{Cap^}): Unit + def store(f: (() -> Unit)^{Cap}): Unit -def run[Cap^](f: Box[Cap]^{Cap^} => Unit): Box[Cap]^{Cap^} = +def run[Cap^](f: Box[Cap]^{Cap} => Unit): Box[Cap]^{Cap} = new Box[Cap]: - private var item: () ->{Cap^} Unit = () => () - def store(f: () ->{Cap^} Unit): Unit = + private var item: () ->{Cap} Unit = () => () + def store(f: () ->{Cap} Unit): Unit = item = f // was error, now ok diff --git a/tests/pos-custom-args/captures/invariant-cc.scala b/tests/pos-custom-args/captures/invariant-cc.scala.disabled similarity index 92% rename from tests/pos-custom-args/captures/invariant-cc.scala rename to tests/pos-custom-args/captures/invariant-cc.scala.disabled index 347b0d2fda64..67e9487f13b2 100644 --- a/tests/pos-custom-args/captures/invariant-cc.scala +++ b/tests/pos-custom-args/captures/invariant-cc.scala.disabled @@ -3,6 +3,8 @@ import scala.annotation.unchecked.uncheckedVariance trait IterableFactory[+CC[_]] extends Pure: + // TODO: elem.type is not a singleton type + def fill[A](n: Int)(elem: => A): CC[A]^{elem} = ??? def fill[A](n1: Int, n2: Int)(elem: => A): CC[(CC[A]^{elem}) @uncheckedVariance]^{elem} = fill[CC[A]^{elem}](n1)(fill(n2)(elem)) 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/setup/a_1.scala b/tests/pos-custom-args/captures/setup/a_1.scala index 21afde8be3ea..3a6ec7ffa773 100644 --- a/tests/pos-custom-args/captures/setup/a_1.scala +++ b/tests/pos-custom-args/captures/setup/a_1.scala @@ -3,4 +3,4 @@ import language.experimental.captureChecking import scala.caps.CapSet trait A: - def f[C^](x: AnyRef^{C^}): Unit + def f[C^](x: AnyRef^{C}): Unit diff --git a/tests/pos-custom-args/captures/setup/b_1.scala b/tests/pos-custom-args/captures/setup/b_1.scala index d5ba925970ba..70c72723c84c 100644 --- a/tests/pos-custom-args/captures/setup/b_1.scala +++ b/tests/pos-custom-args/captures/setup/b_1.scala @@ -2,4 +2,4 @@ import language.experimental.captureChecking import scala.caps.CapSet class B extends A: - def f[C^](x: AnyRef^{C^}): Unit = ??? + def f[C^](x: AnyRef^{C}): Unit = ??? diff --git a/tests/pos-custom-args/captures/setup/b_2.scala b/tests/pos-custom-args/captures/setup/b_2.scala index d5ba925970ba..70c72723c84c 100644 --- a/tests/pos-custom-args/captures/setup/b_2.scala +++ b/tests/pos-custom-args/captures/setup/b_2.scala @@ -2,4 +2,4 @@ import language.experimental.captureChecking import scala.caps.CapSet class B extends A: - def f[C^](x: AnyRef^{C^}): Unit = ??? + def f[C^](x: AnyRef^{C}): Unit = ??? 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/run-tasty-inspector/stdlibExperimentalDefinitions.scala b/tests/run-tasty-inspector/stdlibExperimentalDefinitions.scala index 36075f0a2cee..ab69a5bc679d 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",