diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
index 0a2c0c850e5d..b71af156262f 100644
--- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
+++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala
@@ -588,9 +588,13 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
     case New(_) | Closure(_, _, _) =>
       Pure
     case TypeApply(fn, _) =>
+      val sym = fn.symbol
       if tree.tpe.isInstanceOf[MethodOrPoly] then exprPurity(fn)
-      else if fn.symbol == defn.QuotedTypeModule_of || fn.symbol == defn.Predef_classOf then Pure
-      else if fn.symbol == defn.Compiletime_erasedValue && tree.tpe.dealias.isInstanceOf[ConstantType] then Pure
+      else if sym == defn.QuotedTypeModule_of
+          || sym == defn.Predef_classOf
+          || sym == defn.Compiletime_erasedValue && tree.tpe.dealias.isInstanceOf[ConstantType]
+          || defn.capsErasedValueMethods.contains(sym)
+      then Pure
       else Impure
     case Apply(fn, args) =>
       val factorPurity = minOf(exprPurity(fn), args.map(exprPurity))
@@ -634,6 +638,15 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
 
   def isPureBinding(tree: Tree)(using Context): Boolean = statPurity(tree) >= Pure
 
+  def isPureSyntheticCaseApply(sym: Symbol)(using Context): Boolean =
+    sym.isAllOf(SyntheticMethod)
+    && sym.name == nme.apply
+    && sym.owner.is(Module)
+    && {
+      val cls = sym.owner.companionClass
+      cls.is(Case) && cls.isNoInitsRealClass
+    }
+
   /** Is the application `tree` with function part `fn` known to be pure?
    *  Function value and arguments can still be impure.
    */
@@ -645,6 +658,7 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
 
     tree.tpe.isInstanceOf[ConstantType] && tree.symbol != NoSymbol && isKnownPureOp(tree.symbol) // A constant expression with pure arguments is pure.
     || fn.symbol.isStableMember && fn.symbol.isConstructor // constructors of no-inits classes are stable
+    || isPureSyntheticCaseApply(fn.symbol)
 
   /** The purity level of this reference.
    *  @return
@@ -653,8 +667,6 @@ trait TypedTreeInfo extends TreeInfo[Type] { self: Trees.Instance[Type] =>
    *                    or its type is a constant type
    *    IdempotentPath  if reference is lazy and stable
    *    Impure          otherwise
-   *  @DarkDimius: need to make sure that lazy accessor methods have Lazy and Stable
-   *               flags set.
    */
   def refPurity(tree: Tree)(using Context): PurityLevel = {
     val sym = tree.symbol
diff --git a/compiler/src/dotty/tools/dotc/ast/tpd.scala b/compiler/src/dotty/tools/dotc/ast/tpd.scala
index 991309293c0c..92c20afe7a73 100644
--- a/compiler/src/dotty/tools/dotc/ast/tpd.scala
+++ b/compiler/src/dotty/tools/dotc/ast/tpd.scala
@@ -301,7 +301,7 @@ object tpd extends Trees.Instance[Type] with TypedTreeInfo {
               assert(vparams.hasSameLengthAs(tp.paramNames) && vparams.head.isTerm)
               (vparams.asInstanceOf[List[TermSymbol]], remaining1)
             case nil =>
-              (tp.paramNames.lazyZip(tp.paramInfos).lazyZip(tp.erasedParams).map(valueParam), Nil)
+              (tp.paramNames.lazyZip(tp.paramInfos).lazyZip(tp.paramErasureStatuses).map(valueParam), Nil)
         val (rtp, paramss) = recur(tp.instantiate(vparams.map(_.termRef)), remaining1)
         (rtp, vparams :: paramss)
       case _ =>
diff --git a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala
index 2f5c59c11071..d21e9c7d5064 100644
--- a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala
+++ b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala
@@ -495,15 +495,13 @@ extension (sym: Symbol)
 
   /** Does this symbol allow results carrying the universal capability?
    *  Currently this is true only for function type applies (since their
-   *  results are unboxed) and `erasedValue` since this function is magic in
-   *  that is allows to conjure global capabilies from nothing (aside: can we find a
-   *  more controlled way to achieve this?).
+   *  results are unboxed) and `caps.{$internal,unsafe}.erasedValue` since
+   *  these function are magic in that they allow to conjure global capabilies from nothing.
    *  But it could be generalized to other functions that so that they can take capability
    *  classes as arguments.
    */
   def allowsRootCapture(using Context): Boolean =
-    sym == defn.Compiletime_erasedValue
-    || defn.isFunctionClass(sym.maybeOwner)
+    defn.capsErasedValueMethods.contains(sym) || defn.isFunctionClass(sym.maybeOwner)
 
   /** When applying `sym`, would the result type be unboxed?
    *  This is the case if the result type contains a top-level reference to an enclosing
diff --git a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala
index dccbd0a005d7..e8cc0eb69528 100644
--- a/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala
+++ b/compiler/src/dotty/tools/dotc/cc/CheckCaptures.scala
@@ -576,7 +576,7 @@ class CheckCaptures extends Recheck, SymTransformer:
      *  @param  args the type arguments
      */
     def disallowCapInTypeArgs(fn: Tree, sym: Symbol, args: List[Tree])(using Context): Unit =
-      def isExempt = sym.isTypeTestOrCast || sym == defn.Compiletime_erasedValue
+      def isExempt = sym.isTypeTestOrCast || defn.capsErasedValueMethods.contains(sym)
       if !isExempt then
         val paramNames = atPhase(thisPhase.prev):
           fn.tpe.widenDealias match
diff --git a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
index 81b03d765676..f2e426612eeb 100644
--- a/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
+++ b/compiler/src/dotty/tools/dotc/core/CheckRealizable.scala
@@ -48,8 +48,6 @@ object CheckRealizable {
 
   def boundsRealizability(tp: Type)(using Context): Realizability =
     new CheckRealizable().boundsRealizability(tp)
-
-  private val LateInitializedFlags = Lazy | Erased
 }
 
 /** Compute realizability status.
@@ -72,7 +70,7 @@ class CheckRealizable(using Context) {
   /** Is symbol's definitition a lazy or erased val?
    *  (note we exclude modules here, because their realizability is ensured separately)
    */
-  private def isLateInitialized(sym: Symbol) = sym.isOneOf(LateInitializedFlags, butNot = Module)
+  private def isLateInitialized(sym: Symbol) = sym.is(Lazy, butNot = Module)
 
   /** The realizability status of given type `tp`*/
   def realizability(tp: Type): Realizability = tp.dealias match {
@@ -184,7 +182,7 @@ class CheckRealizable(using Context) {
   private def memberRealizability(tp: Type) = {
     def checkField(sofar: Realizability, fld: SingleDenotation): Realizability =
       sofar andAlso {
-        if (checkedFields.contains(fld.symbol) || fld.symbol.isOneOf(Private | Mutable | LateInitializedFlags))
+        if (checkedFields.contains(fld.symbol) || fld.symbol.isOneOf(Private | Mutable | Lazy))
           // if field is private it cannot be part of a visible path
           // if field is mutable it cannot be part of a path
           // if field is lazy or erased it does not need to be initialized when the owning object is
diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala
index 381caa775dbd..3aaf966597c3 100644
--- a/compiler/src/dotty/tools/dotc/core/Definitions.scala
+++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala
@@ -1004,9 +1004,11 @@ 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_erasedValue: Symbol = CapsInternalModule.requiredMethod("erasedValue")
     @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")
+    @tu lazy val Caps_unsafeErasedValue: Symbol = CapsUnsafeModule.requiredMethod("unsafeErasedValue")
     @tu lazy val Caps_ContainsTrait: TypeSymbol = CapsModule.requiredType("Contains")
     @tu lazy val Caps_ContainsModule: Symbol = requiredModule("scala.caps.Contains")
     @tu lazy val Caps_containsImpl: TermSymbol = Caps_ContainsModule.requiredMethod("containsImpl")
@@ -1558,6 +1560,11 @@ class Definitions {
   @tu lazy val pureSimpleClasses =
     Set(StringClass, NothingClass, NullClass) ++ ScalaValueClasses()
 
+  @tu lazy val capsErasedValueMethods =
+    Set(Caps_erasedValue, Caps_unsafeErasedValue)
+  @tu lazy val erasedValueMethods =
+    capsErasedValueMethods + Compiletime_erasedValue
+
   @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)
@@ -2001,7 +2008,9 @@ class Definitions {
 
   /** A allowlist of Scala-2 classes that are known to be pure */
   def isAssuredNoInits(sym: Symbol): Boolean =
-    (sym `eq` SomeClass) || isTupleClass(sym)
+    (sym `eq` SomeClass)
+    || isTupleClass(sym)
+    || sym.is(Module) && isAssuredNoInits(sym.companionClass)
 
   /** If `cls` is Tuple1..Tuple22, add the corresponding *: type as last parent to `parents` */
   def adjustForTuple(cls: ClassSymbol, tparams: List[TypeSymbol], parents: List[Type]): List[Type] = {
diff --git a/compiler/src/dotty/tools/dotc/core/Flags.scala b/compiler/src/dotty/tools/dotc/core/Flags.scala
index c040d3e206b9..9fdc640d4d24 100644
--- a/compiler/src/dotty/tools/dotc/core/Flags.scala
+++ b/compiler/src/dotty/tools/dotc/core/Flags.scala
@@ -569,7 +569,6 @@ 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                      = PhantomSymbol | Erased
   val ConstructorProxyModule: FlagSet        = PhantomSymbol | Module
   val CaptureParam: FlagSet                  = PhantomSymbol | StableRealizable | Synthetic
   val DefaultParameter: FlagSet              = HasDefault | Param                             // A Scala 2x default parameter
diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
index bd43578e3d53..2cac0a6d5b2f 100644
--- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
+++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala
@@ -1051,8 +1051,13 @@ object SymDenotations {
       && owner.ne(defn.StringContextClass)
 
     /** An erased value or an erased inline method or field */
+    def isErased(using Context): Boolean =
+      is(Erased) || defn.erasedValueMethods.contains(symbol)
+
+    /** An erased value, a phantom symbol or an erased inline method or field */
     def isEffectivelyErased(using Context): Boolean =
-      isOneOf(EffectivelyErased)
+      isErased
+      || is(PhantomSymbol)
       || is(Inline) && !isRetainedInline && !hasAnnotation(defn.ScalaStaticAnnot)
 
     /** Is this a member that will become public in the generated binary */
diff --git a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
index eb03a2b1c05d..5753d311baa9 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeComparer.scala
@@ -2387,7 +2387,7 @@ class TypeComparer(@constructorOnly initctx: Context) extends ConstraintHandling
         formals2.isEmpty
     }
     // If methods have erased parameters, then the erased parameters must match
-    val erasedValid = (!tp1.hasErasedParams && !tp2.hasErasedParams) || (tp1.erasedParams == tp2.erasedParams)
+    val erasedValid = (!tp1.hasErasedParams && !tp2.hasErasedParams) || (tp1.paramErasureStatuses == tp2.paramErasureStatuses)
 
     erasedValid && loop(tp1.paramInfos, tp2.paramInfos)
   }
diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
index 83f087239477..2e6fa7d94d43 100644
--- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
+++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala
@@ -697,7 +697,7 @@ class TypeErasure(sourceLanguage: SourceLanguage, semiEraseVCs: Boolean, isConst
         val (names, formals0) = if tp.hasErasedParams then
           tp.paramNames
             .zip(tp.paramInfos)
-            .zip(tp.erasedParams)
+            .zip(tp.paramErasureStatuses)
             .collect{ case (param, isErased) if !isErased => param }
             .unzip
         else (tp.paramNames, tp.paramInfos)
diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala
index 61b3b958fca3..1b59faf81a6f 100644
--- a/compiler/src/dotty/tools/dotc/core/Types.scala
+++ b/compiler/src/dotty/tools/dotc/core/Types.scala
@@ -3931,7 +3931,7 @@ object Types extends TypeUtils {
           case tp: MethodType =>
             val params = if (hasErasedParams)
               tp.paramInfos
-                .zip(tp.erasedParams)
+                .zip(tp.paramErasureStatuses)
                 .collect { case (param, isErased) if !isErased => param }
             else tp.paramInfos
             resultSignature.prependTermParams(params, sourceLanguage)
@@ -4163,7 +4163,7 @@ object Types extends TypeUtils {
     final override def isContextualMethod: Boolean =
       companion.eq(ContextualMethodType)
 
-    def erasedParams(using Context): List[Boolean] =
+    def paramErasureStatuses(using Context): List[Boolean] =
       paramInfos.map(p => p.hasAnnotation(defn.ErasedParamAnnot))
 
     def nonErasedParamCount(using Context): Int =
diff --git a/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala b/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala
index 3edb323e6b3b..a1058b18e32c 100644
--- a/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala
+++ b/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala
@@ -172,6 +172,19 @@ class InlineReducer(inliner: Inliner)(using Context):
 
     val isImplicit = scrutinee.isEmpty
 
+    val unusable: util.EqHashSet[Symbol] = util.EqHashSet()
+
+    /** Adjust internaly generated value definitions;
+     *   - If the RHS refers to an erased symbol, mark the val as erased
+     *   - If the RHS refers to an erased symbol, mark the val as unsuable
+     */
+    def adjustErased(sym: TermSymbol, rhs: Tree): Unit =
+      rhs.foreachSubTree:
+        case id: Ident if id.symbol.isErased =>
+          sym.setFlag(Erased)
+          if unusable.contains(id.symbol) then unusable += sym
+        case _ =>
+
     /** Try to match pattern `pat` against scrutinee reference `scrut`. If successful add
      *  bindings for variables bound in this pattern to `caseBindingMap`.
      */
@@ -184,10 +197,11 @@ class InlineReducer(inliner: Inliner)(using Context):
       /** Create a binding of a pattern bound variable with matching part of
        *  scrutinee as RHS and type that corresponds to RHS.
        */
-      def newTermBinding(sym: TermSymbol, rhs: Tree): Unit = {
-        val copied = sym.copy(info = rhs.tpe.widenInlineScrutinee, coord = sym.coord, flags = sym.flags &~ Case).asTerm
+      def newTermBinding(sym: TermSymbol, rhs: Tree): Unit =
+        val copied = sym.copy(info = rhs.tpe.widenInlineScrutinee, coord = sym.coord,
+          flags = sym.flags &~ Case).asTerm
+        adjustErased(copied, rhs)
         caseBindingMap += ((sym, ValDef(copied, constToLiteral(rhs)).withSpan(sym.span)))
-      }
 
       def newTypeBinding(sym: TypeSymbol, alias: Type): Unit = {
         val copied = sym.copy(info = TypeAlias(alias), coord = sym.coord).asType
@@ -306,6 +320,7 @@ class InlineReducer(inliner: Inliner)(using Context):
                 case (Nil, Nil) => true
                 case (pat :: pats1, selector :: selectors1) =>
                   val elem = newSym(InlineBinderName.fresh(), Synthetic, selector.tpe.widenInlineScrutinee).asTerm
+                  adjustErased(elem, selector)
                   val rhs = constToLiteral(selector)
                   elem.defTree = rhs
                   caseBindingMap += ((NoSymbol, ValDef(elem, rhs).withSpan(elem.span)))
@@ -341,6 +356,19 @@ class InlineReducer(inliner: Inliner)(using Context):
     val scrutineeSym = newSym(InlineScrutineeName.fresh(), Synthetic, scrutType).asTerm
     val scrutineeBinding = normalizeBinding(ValDef(scrutineeSym, scrutinee))
 
+    // If scrutinee has embedded references to `compiletime.erasedValue` or to
+    // other erased values, mark scrutineeSym as Erased. In addition, if scrutinee
+    // is not a pure expression, mark scrutineeSym as unusable. The reason is that
+    // scrutinee would then fail the tests in erasure that demand that the RHS of
+    // an erased val is a pure expression. At the end of the inline match reduction
+    // we throw out all unusable vals and check that the remaining code does not refer
+    // to unusable symbols.
+    // Note that compiletime.erasedValue is treated as erased but not pure, so scrutinees
+    // containing references to it becomes unusable.
+    if scrutinee.existsSubTree(_.symbol.isErased) then
+      scrutineeSym.setFlag(Erased)
+      if !tpd.isPureExpr(scrutinee) then unusable += scrutineeSym
+
     def reduceCase(cdef: CaseDef): MatchReduxWithGuard = {
       val caseBindingMap = new mutable.ListBuffer[(Symbol, MemberDef)]()
 
@@ -382,7 +410,25 @@ class InlineReducer(inliner: Inliner)(using Context):
           case _ => None
     }
 
-    recur(cases)
+    for (bindings, expr) <- recur(cases) yield
+      // drop unusable vals and check that no referenes to unusable symbols remain
+      val cleanupUnusable = new TreeMap:
+        override def transform(tree: Tree)(using Context): Tree =
+          tree match
+            case tree: ValDef if unusable.contains(tree.symbol) => EmptyTree
+            case id: Ident if unusable.contains(id.symbol) =>
+              report.error(
+                em"""${id.symbol} is unusable in ${ctx.owner} because it refers to an erased expression
+                    |in the selector of an inline match that reduces to
+                    |
+                    |${Block(bindings, expr)}""",
+                tree.srcPos)
+              tree
+            case _ => super.transform(tree)
+
+      val bindings1 = bindings.mapConserve(cleanupUnusable.transform).collect:
+        case mdef: MemberDef => mdef
+      (bindings1, cleanupUnusable.transform(expr))
   }
 end InlineReducer
 
diff --git a/compiler/src/dotty/tools/dotc/quoted/Interpreter.scala b/compiler/src/dotty/tools/dotc/quoted/Interpreter.scala
index dbc2694dc891..816bac14ddd2 100644
--- a/compiler/src/dotty/tools/dotc/quoted/Interpreter.scala
+++ b/compiler/src/dotty/tools/dotc/quoted/Interpreter.scala
@@ -127,8 +127,8 @@ class Interpreter(pos: SrcPos, classLoader0: ClassLoader)(using Context):
       case fnType: MethodType =>
         val argTypes = fnType.paramInfos
         assert(argss.head.size == argTypes.size)
-        val nonErasedArgs = argss.head.lazyZip(fnType.erasedParams).collect { case (arg, false) => arg }.toList
-        val nonErasedArgTypes = fnType.paramInfos.lazyZip(fnType.erasedParams).collect { case (arg, false) => arg }.toList
+        val nonErasedArgs = argss.head.lazyZip(fnType.paramErasureStatuses).collect { case (arg, false) => arg }.toList
+        val nonErasedArgTypes = fnType.paramInfos.lazyZip(fnType.paramErasureStatuses).collect { case (arg, false) => arg }.toList
         assert(nonErasedArgs.size == nonErasedArgTypes.size)
         interpretArgsGroup(nonErasedArgs, nonErasedArgTypes) ::: interpretArgs(argss.tail, fnType.resType)
       case fnType: AppliedType if defn.isContextFunctionType(fnType) =>
diff --git a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala
index 96942f913934..99e1435d0e65 100644
--- a/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/ErrorMessageID.scala
@@ -229,6 +229,7 @@ enum ErrorMessageID(val isActive: Boolean = true) extends java.lang.Enum[ErrorMe
   case PointlessAppliedConstructorTypeID // errorNumber: 213
   case IllegalContextBoundsID // errorNumber: 214
   case NamedPatternNotApplicableID // errorNumber: 215
+  case ErasedNotPureID // errornumber 216
 
   def errorNumber = ordinal - 1
 
diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala
index e30ec66eede2..21f97e8b7abf 100644
--- a/compiler/src/dotty/tools/dotc/reporting/messages.scala
+++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala
@@ -3538,4 +3538,36 @@ final class NamedPatternNotApplicable(selectorType: Type)(using Context) extends
   override protected def msg(using Context): String =
     i"Named patterns cannot be used with $selectorType, because it is not a named tuple or case class"
 
-  override protected def explain(using Context): String = ""
\ No newline at end of file
+  override protected def explain(using Context): String = ""
+
+final class ErasedNotPure(tree: tpd.Tree, isArgument: Boolean, isImplicit: Boolean)(using Context) extends TypeMsg(ErasedNotPureID):
+  def what =
+    if isArgument then s"${if isImplicit then "implicit " else ""}argument to an erased parameter"
+    else "right-hand-side of an erased value"
+  override protected def msg(using Context): String =
+    i"$what fails to be a pure expression"
+
+  override protected def explain(using Context): String =
+    def alternatives =
+      if tree.symbol == defn.Compiletime_erasedValue then
+        i"""An accepted (but unsafe) alternative for this expression uses function
+           |
+           |      caps.unsafe.unsafeErasedValue
+           |
+           |instead."""
+      else
+        """A pure expression is an expression that is clearly side-effect free and terminating.
+          |Some examples of pure expressions are:
+          |  - literals,
+          |  - references to values,
+          |  - side-effect-free instance creations,
+          |  - applications of inline functions to pure arguments."""
+
+    i"""The $what must be a pure expression, but I found:
+       |
+       |  $tree
+       |
+       |This expression is not classified to be pure.
+       |$alternatives"""
+end ErasedNotPure
+
diff --git a/compiler/src/dotty/tools/dotc/transform/Erasure.scala b/compiler/src/dotty/tools/dotc/transform/Erasure.scala
index 3503c707aed9..66f4db32be9e 100644
--- a/compiler/src/dotty/tools/dotc/transform/Erasure.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Erasure.scala
@@ -583,6 +583,12 @@ object Erasure {
       checkNotErasedClass(tree)
     end checkNotErased
 
+    def checkPureErased(tree: untpd.Tree, isArgument: Boolean, isImplicit: Boolean = false)(using Context): Unit =
+      val tree1 = tree.asInstanceOf[tpd.Tree]
+      inContext(preErasureCtx):
+        if !tpd.isPureExpr(tree1) then
+          report.error(ErasedNotPure(tree1, isArgument, isImplicit), tree1.srcPos)
+
     private def checkNotErasedClass(tp: Type, tree: untpd.Tree)(using Context): Unit = tp match
       case JavaArrayType(et) =>
         checkNotErasedClass(et, tree)
@@ -848,7 +854,13 @@ object Erasure {
       val origFunType = origFun.tpe.widen(using preErasureCtx)
       val ownArgs = origFunType match
         case mt: MethodType if mt.hasErasedParams =>
-          args.zip(mt.erasedParams).collect { case (arg, false) => arg }
+          args.lazyZip(mt.paramErasureStatuses).flatMap: (arg, isErased) =>
+            if isErased then
+              checkPureErased(arg, isArgument = true,
+                isImplicit = mt.isImplicitMethod && arg.span.isSynthetic)
+              Nil
+            else
+              arg :: Nil
         case _ => args
       val fun1 = typedExpr(fun, AnyFunctionProto)
       fun1.tpe.widen match
@@ -916,8 +928,10 @@ object Erasure {
       }
 
     override def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree =
-      if (sym.isEffectivelyErased) erasedDef(sym)
-      else
+      if sym.isEffectivelyErased then
+        checkPureErased(vdef.rhs, isArgument = false)
+        erasedDef(sym)
+      else trace(i"erasing $vdef"):
         checkNotErasedClass(sym.info, vdef)
         super.typedValDef(untpd.cpy.ValDef(vdef)(
           tpt = untpd.TypedSplice(TypeTree(sym.info).withSpan(vdef.tpt.span))), sym)
diff --git a/compiler/src/dotty/tools/dotc/transform/Getters.scala b/compiler/src/dotty/tools/dotc/transform/Getters.scala
index 6e6d84a9eaae..11adf4da83d5 100644
--- a/compiler/src/dotty/tools/dotc/transform/Getters.scala
+++ b/compiler/src/dotty/tools/dotc/transform/Getters.scala
@@ -90,7 +90,7 @@ class Getters extends MiniPhase with SymTransformer { thisPhase =>
     d1
   }
 
-  private val NoGetterNeededFlags = Method | Param | JavaDefined | JavaStatic | PhantomSymbol
+  private val NoGetterNeededFlags = Method | Param | JavaDefined | JavaStatic | PhantomSymbol | Erased
 
   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 5e2ff2d43283..2f1e4a8b2b4f 100644
--- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala
+++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala
@@ -408,7 +408,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
         case app: Apply =>
           val methType = app.fun.tpe.widen.asInstanceOf[MethodType]
           if (methType.hasErasedParams)
-            for (arg, isErased) <- app.args.lazyZip(methType.erasedParams) do
+            for (arg, isErased) <- app.args.lazyZip(methType.paramErasureStatuses) do
               if isErased then
                 if methType.isResultDependent then
                   Checking.checkRealizable(arg.tpe, arg.srcPos, "erased argument")
@@ -475,7 +475,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
         case tree: ValDef =>
           annotateExperimentalCompanion(tree.symbol)
           registerIfHasMacroAnnotations(tree)
-          checkErasedDef(tree)
+          //checkErasedDef(tree)
           Checking.checkPolyFunctionType(tree.tpt)
           val tree1 = cpy.ValDef(tree)(tpt = makeOverrideTypeDeclared(tree.symbol, tree.tpt))
           if tree1.removeAttachment(desugar.UntupledParam).isDefined then
@@ -483,7 +483,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase =>
           processValOrDefDef(super.transform(tree1))
         case tree: DefDef =>
           registerIfHasMacroAnnotations(tree)
-          checkErasedDef(tree)
+          //checkErasedDef(tree)
           Checking.checkPolyFunctionType(tree.tpt)
           annotateContextResults(tree)
           val tree1 = cpy.DefDef(tree)(tpt = makeOverrideTypeDeclared(tree.symbol, tree.tpt))
diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala
index df4350f1eb05..56599a489732 100644
--- a/compiler/src/dotty/tools/dotc/typer/Checking.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala
@@ -607,10 +607,12 @@ object Checking {
       fail(ModifierNotAllowedForDefinition(Flags.Infix, s"A top-level ${sym.showKind} cannot be infix."))
     if sym.isUpdateMethod && !sym.owner.derivesFrom(defn.Caps_Mutable) then
       fail(em"Update methods can only be used as members of classes extending the `Mutable` trait")
-    checkApplicable(Erased,
-      !sym.is(Lazy, butNot = Given)
-      && !sym.isMutableVarOrAccessor
-      && (!sym.isType || sym.isClass))
+    val unerasable =
+      sym.is(Lazy, butNot = Given)
+      || sym.is(Method, butNot = Macro)
+      || sym.is(Mutable)
+      || sym.isType && !sym.isClass
+    checkApplicable(Erased, !unerasable)
     checkCombination(Final, Open)
     checkCombination(Sealed, Open)
     checkCombination(Final, Sealed)
diff --git a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala
index 26d03db4b7dc..55778017b76f 100644
--- a/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala
+++ b/compiler/src/dotty/tools/dotc/typer/EtaExpansion.scala
@@ -300,9 +300,9 @@ object EtaExpansion extends LiftImpure {
     val body = Apply(lifted, ids)
     if (mt.isContextualMethod) body.setApplyKind(ApplyKind.Using)
     val fn =
-      if (mt.isContextualMethod) new untpd.FunctionWithMods(params, body, Modifiers(Given), mt.erasedParams)
-      else if (mt.isImplicitMethod) new untpd.FunctionWithMods(params, body, Modifiers(Implicit), mt.erasedParams)
-      else if (mt.hasErasedParams) new untpd.FunctionWithMods(params, body, Modifiers(), mt.erasedParams)
+      if (mt.isContextualMethod) new untpd.FunctionWithMods(params, body, Modifiers(Given), mt.paramErasureStatuses)
+      else if (mt.isImplicitMethod) new untpd.FunctionWithMods(params, body, Modifiers(Implicit), mt.paramErasureStatuses)
+      else if (mt.hasErasedParams) new untpd.FunctionWithMods(params, body, Modifiers(), mt.paramErasureStatuses)
       else untpd.Function(params, body)
     if (defs.nonEmpty) untpd.Block(defs.toList map (untpd.TypedSplice(_)), fn) else fn
   }
diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala
index 4f596776d497..362866866e4a 100644
--- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala
@@ -231,7 +231,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
     case PreciseConstrained(tp, true) =>
       if tp.isSingletonBounded(frozen = false) then
         withNoErrors:
-          ref(defn.Compiletime_erasedValue).appliedToType(formal).withSpan(span)
+          ref(defn.Caps_erasedValue).appliedToType(formal).withSpan(span)
       else
         withErrors(i"$tp is not a singleton")
     case _ =>
@@ -240,7 +240,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context):
   val synthesizedPrecise: SpecialHandler = (formal, span) => formal match
     case PreciseConstrained(tp, false) =>
       withNoErrors:
-        ref(defn.Compiletime_erasedValue).appliedToType(formal).withSpan(span)
+        ref(defn.Caps_erasedValue).appliedToType(formal).withSpan(span)
     case _ =>
       EmptyTreeNoError
 
diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala
index 96d8dbffccfb..6cc7dba35e26 100644
--- a/compiler/src/dotty/tools/dotc/typer/Typer.scala
+++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala
@@ -1769,7 +1769,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
       if (mt.isParamDependent)
         report.error(em"$mt is an illegal function type because it has inter-parameter dependencies", tree.srcPos)
       // Restart typechecking if there are erased classes that we want to mark erased
-      if mt.erasedParams.zip(mt.paramInfos.map(_.isErasedClass)).exists((paramErased, classErased) => classErased && !paramErased) then
+      if mt.paramErasureStatuses.zip(mt.paramInfos.map(_.isErasedClass)).exists((paramErased, classErased) => classErased && !paramErased) then
         val newParams = params3.zipWithConserve(mt.paramInfos.map(_.isErasedClass)) { (arg, isErasedClass) =>
           if isErasedClass then arg.withAddedFlags(Erased) else arg
         }
@@ -2392,7 +2392,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
       untpd.ValDef(
           CanThrowEvidenceName.fresh(),
           untpd.TypeTree(defn.CanThrowClass.typeRef.appliedTo(tp)),
-          untpd.ref(defn.Compiletime_erasedValue))
+          untpd.ref(defn.Caps_erasedValue))
         .withFlags(Given | Final | Erased)
         .withSpan(expr.span)
     val caughtExceptions =
@@ -2971,14 +2971,6 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
     EmptyTree
 
   def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(using Context): Tree = if !sym.info.exists then retractDefDef(sym) else ctx.profiler.onTypedDef(sym) {
-
-    // TODO: - Remove this when `scala.language.experimental.erasedDefinitions` is no longer experimental.
-    //       - Modify signature to `erased def erasedValue[T]: T`
-    if sym.eq(defn.Compiletime_erasedValue) then
-      // scala.compiletime.erasedValue should be `erased` but we cannot add this in the source.
-      // The library cannot use experimental language features,
-      // hence we special case it until `erased` is no longer experimental.
-      sym.setFlag(Erased)
     val DefDef(name, paramss, tpt, _) = ddef
     checkNonRootName(ddef.name, ddef.nameSpan)
     completeAnnotations(ddef, sym)
@@ -3809,7 +3801,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
     }
 
     val erasedParams = pt match {
-      case defn.PolyFunctionOf(mt: MethodType) => mt.erasedParams
+      case defn.PolyFunctionOf(mt: MethodType) => mt.paramErasureStatuses
       case _ => paramTypes.map(_ => false)
     }
 
diff --git a/compiler/src/dotty/tools/dotc/util/DiffUtil.scala b/compiler/src/dotty/tools/dotc/util/DiffUtil.scala
index 31acc91caa2e..126cff9b9c65 100644
--- a/compiler/src/dotty/tools/dotc/util/DiffUtil.scala
+++ b/compiler/src/dotty/tools/dotc/util/DiffUtil.scala
@@ -103,7 +103,6 @@ object DiffUtil {
         case Deleted(str) => deleted(str)
       }.mkString
 
-    (expectedDiff, actualDiff)
     val pad = " " * 0.max(expectedSize - expected.length)
 
     expectedDiff + pad + "  |  " + actualDiff
diff --git a/compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala b/compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala
index 3790174526b3..e3d5355eaffa 100644
--- a/compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala
+++ b/compiler/src/scala/quoted/runtime/impl/QuoteMatcher.scala
@@ -448,7 +448,7 @@ class QuoteMatcher(debug: Boolean) {
                   def matchErasedParams(sctype: Type, pttype: Type): optional[MatchingExprs] =
                     (sctype, pttype) match
                       case (sctpe: MethodType, pttpe: MethodType) =>
-                        if sctpe.erasedParams.sameElements(pttpe.erasedParams) then
+                        if sctpe.paramErasureStatuses.sameElements(pttpe.paramErasureStatuses) then
                           matchErasedParams(sctpe.resType, pttpe.resType)
                         else
                           notMatched
diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
index 852d7ee8b20f..fdd16963d33b 100644
--- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
+++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala
@@ -2288,7 +2288,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler
             case _ => MethodTypeKind.Plain
         def param(idx: Int): TypeRepr = self.newParamRef(idx)
 
-        def erasedParams: List[Boolean] = self.erasedParams
+        def erasedParams: List[Boolean] = self.paramErasureStatuses
         def hasErasedParams: Boolean = self.hasErasedParams
       end extension
     end MethodTypeMethods
diff --git a/compiler/test-resources/type-printer/test-definitions b/compiler/test-resources/type-printer/test-definitions
index cdda5f65cb0e..6566496d3181 100644
--- a/compiler/test-resources/type-printer/test-definitions
+++ b/compiler/test-resources/type-printer/test-definitions
@@ -18,8 +18,3 @@ scala> trait E
 
 scala> implicit def x: Int = 1
 def x: Int
-
-scala> import scala.language.experimental.erasedDefinitions
-
-scala> erased def y: Int = 1
-def y: Int
diff --git a/docs/_docs/reference/experimental/erased-defs.md b/docs/_docs/reference/experimental/erased-defs.md
index d266cd6c9d19..4be4498e1058 100644
--- a/docs/_docs/reference/experimental/erased-defs.md
+++ b/docs/_docs/reference/experimental/erased-defs.md
@@ -4,7 +4,7 @@ title: "Erased Definitions"
 nightlyOf: https://docs.scala-lang.org/scala3/reference/experimental/erased-defs.html
 ---
 
-`erased` is a modifier that expresses that some definition or expression is erased by the compiler instead of being represented in the compiled output. It is not yet part of the Scala language standard. To enable `erased`, turn on the language feature
+`erased` is a modifier that expresses that some value or parameter is erased by the compiler instead of being represented in the compiled output. It is not yet part of the Scala language standard. To enable `erased`, turn on the language feature
 [`experimental.erasedDefinitions`](https://scala-lang.org/api/3.x/scala/runtime/stdLibPatches/language$$experimental$$erasedDefinitions$.html). This can be done with a language import
 ```scala
 import scala.language.experimental.erasedDefinitions
@@ -74,9 +74,9 @@ def methodWithErasedInt2(erased i: Int): Int =
   methodWithErasedInt1(i) // OK
 ```
 
-Not only parameters can be marked as erased, `val` and `def` can also be marked
-with `erased`. These will also only be usable as arguments to `erased`
-parameters.
+Besides parameters, `val` definitions can also be marked with `erased`.
+These will also only be usable as arguments to `erased` parameters or
+as part of the definitions of other erased `val`s.
 
 ```scala
 erased val erasedEvidence: Ev = ...
@@ -85,7 +85,7 @@ methodWithErasedEv(erasedEvidence, 40) // 42
 
 ## What happens with erased values at runtime?
 
-As `erased` are guaranteed not to be used in computations, they can and will be
+As `erased` vals and parameters are guaranteed not to be used in computations, they can and will be
 erased.
 
 ```scala
@@ -130,7 +130,7 @@ class IsOff[S <: State]
 object IsOff:
   // will not be called at runtime for turnedOn, the
   // compiler will only require that this evidence exists
-  given IsOff[Off] = new IsOff[Off]
+  erased given IsOff[Off] = new IsOff[Off]
 
 @implicitNotFound("State must be On")
 class IsOn[S <: State]
@@ -151,14 +151,7 @@ object Machine:
   val m = Machine.newMachine()
   m.turnedOn
   m.turnedOn.turnedOff
-
-  // m.turnedOff
-  //            ^
-  //            State must be On
-
-  // m.turnedOn.turnedOn
-  //                    ^
-  //                    State must be Off
+  m.turnedOn.turnedOn // error: State must be Off
 ```
 
 Note that in [Compile-time operations](../metaprogramming/compiletime-ops.md#erasedvalue) we discussed `erasedValue` and inline
diff --git a/library/src/scala/CanThrow.scala b/library/src/scala/CanThrow.scala
index 485dcecb37df..46164d0133ea 100644
--- a/library/src/scala/CanThrow.scala
+++ b/library/src/scala/CanThrow.scala
@@ -12,5 +12,5 @@ erased class CanThrow[-E <: Exception] extends caps.SharedCapability
 
 @experimental
 object unsafeExceptions:
-  given canThrowAny: CanThrow[Exception] = compiletime.erasedValue
+  inline given canThrowAny: CanThrow[Exception] = caps.unsafe.unsafeErasedValue
 
diff --git a/library/src/scala/caps/package.scala b/library/src/scala/caps/package.scala
index fedfd7400e25..98df6ce5219c 100644
--- a/library/src/scala/caps/package.scala
+++ b/library/src/scala/caps/package.scala
@@ -110,6 +110,13 @@ object internal:
    */
   final class inferredDepFun extends annotation.StaticAnnotation
 
+  /** An erasedValue issued internally by the compiler. Unlike the
+   *  user-accessible compiletime.erasedValue, this version is assumed
+   *  to be a pure expression, hence capability safe. The compiler generates this
+   *  version only where it is known that a value can be generated.
+   */
+  def erasedValue[T]: T = ???
+
 end internal
 
 @experimental
@@ -135,4 +142,11 @@ object unsafe:
    */
   def unsafeAssumeSeparate(op: Any): op.type = op
 
+  /** An unsafe variant of erasedValue that can be used as an escape hatch. Unlike the
+   *  user-accessible compiletime.erasedValue, this version is assumed
+   *  to be a pure expression, hence capability safe. But there is no proof
+   *  of realizability, hence it is unsafe.
+   */
+  def unsafeErasedValue[T]: T = ???
+
 end unsafe
diff --git a/library/src/scala/compiletime/package.scala b/library/src/scala/compiletime/package.scala
index 8215ae2452a3..1a161ebd4a03 100644
--- a/library/src/scala/compiletime/package.scala
+++ b/library/src/scala/compiletime/package.scala
@@ -23,7 +23,6 @@ import annotation.{compileTimeOnly, experimental}
  *  the branches.
  *  @syntax markdown
  */
-// TODO add `erased` once it is not an experimental feature anymore
 def erasedValue[T]: T = erasedValue[T]
 
 /** Used as the initializer of a mutable class or object field, like this:
diff --git a/tests/init/warn/inner30.scala b/tests/init/warn/inner30.scala
index d9b1eec3d6b1..1fd112579263 100644
--- a/tests/init/warn/inner30.scala
+++ b/tests/init/warn/inner30.scala
@@ -8,7 +8,7 @@ class Scanners {
 
   class Scanner {
     def foo() =
-      Conc(Run('a', 3), Run('b', 4))
+      Conc(Run('a', 3), Run('b', 4))  // warn
       new LookAheadScanner
 
     class LookAheadScanner() extends Scanner
diff --git a/tests/neg/erased-1.scala b/tests/invalid/neg/erased-1.scala
similarity index 100%
rename from tests/neg/erased-1.scala
rename to tests/invalid/neg/erased-1.scala
diff --git a/tests/neg/erased-2.scala b/tests/invalid/neg/erased-2.scala
similarity index 100%
rename from tests/neg/erased-2.scala
rename to tests/invalid/neg/erased-2.scala
diff --git a/tests/neg/erased-3.scala b/tests/invalid/neg/erased-3.scala
similarity index 100%
rename from tests/neg/erased-3.scala
rename to tests/invalid/neg/erased-3.scala
diff --git a/tests/neg/erased-args-lifted.scala b/tests/invalid/neg/erased-args-lifted.scala
similarity index 87%
rename from tests/neg/erased-args-lifted.scala
rename to tests/invalid/neg/erased-args-lifted.scala
index dfa7b74ee3d4..a2f6a654429f 100644
--- a/tests/neg/erased-args-lifted.scala
+++ b/tests/invalid/neg/erased-args-lifted.scala
@@ -2,7 +2,7 @@
 
 object Test {
   def foo(a: Int)(b: Int, c: Int) = 42
-  erased def bar(erased i: Int): Int = {
+  inline def bar(erased i: Int): Int = {
     println(1)
     42
   }
diff --git a/tests/neg/erased-implicit.scala b/tests/invalid/neg/erased-implicit.scala
similarity index 100%
rename from tests/neg/erased-implicit.scala
rename to tests/invalid/neg/erased-implicit.scala
diff --git a/tests/neg/erased-params.scala b/tests/invalid/neg/erased-params.scala
similarity index 100%
rename from tests/neg/erased-params.scala
rename to tests/invalid/neg/erased-params.scala
diff --git a/tests/pos/i11743.scala b/tests/invalid/pos/i11743.scala
similarity index 81%
rename from tests/pos/i11743.scala
rename to tests/invalid/pos/i11743.scala
index ae524ca01ad6..3114383b3433 100644
--- a/tests/pos/i11743.scala
+++ b/tests/invalid/pos/i11743.scala
@@ -2,7 +2,7 @@ import language.experimental.erasedDefinitions
 import scala.compiletime.erasedValue
 type UnivEq[A]
 object UnivEq:
-  erased def force[A]: UnivEq[A] = erasedValue
+  inline def force[A]: UnivEq[A] = erasedValue
   extension [A](erased proof: UnivEq[A])
     inline def univEq(a: A, b: A): Boolean =
       a == b
diff --git a/tests/pos/i17584a.scala b/tests/invalid/pos/i17584a.scala
similarity index 100%
rename from tests/pos/i17584a.scala
rename to tests/invalid/pos/i17584a.scala
diff --git a/tests/run/erased-1.check b/tests/invalid/run/erased-1.check
similarity index 100%
rename from tests/run/erased-1.check
rename to tests/invalid/run/erased-1.check
diff --git a/tests/run/erased-1.scala b/tests/invalid/run/erased-1.scala
similarity index 100%
rename from tests/run/erased-1.scala
rename to tests/invalid/run/erased-1.scala
diff --git a/tests/run/erased-10.check b/tests/invalid/run/erased-10.check
similarity index 100%
rename from tests/run/erased-10.check
rename to tests/invalid/run/erased-10.check
diff --git a/tests/run/erased-10.scala b/tests/invalid/run/erased-10.scala
similarity index 92%
rename from tests/run/erased-10.scala
rename to tests/invalid/run/erased-10.scala
index 004d07b4de37..ce8c8a42de4c 100644
--- a/tests/run/erased-10.scala
+++ b/tests/invalid/run/erased-10.scala
@@ -10,7 +10,7 @@ object Test {
     println("pacFun4")
   }
 
-  erased def inky: Int = {
+  inline def inky: Int = {
     println("inky") // in erased function
     42
   }
diff --git a/tests/run/erased-11.check b/tests/invalid/run/erased-11.check
similarity index 100%
rename from tests/run/erased-11.check
rename to tests/invalid/run/erased-11.check
diff --git a/tests/run/erased-11.scala b/tests/invalid/run/erased-11.scala
similarity index 100%
rename from tests/run/erased-11.scala
rename to tests/invalid/run/erased-11.scala
diff --git a/tests/run/erased-12.check b/tests/invalid/run/erased-12.check
similarity index 100%
rename from tests/run/erased-12.check
rename to tests/invalid/run/erased-12.check
diff --git a/tests/run/erased-12.scala b/tests/invalid/run/erased-12.scala
similarity index 100%
rename from tests/run/erased-12.scala
rename to tests/invalid/run/erased-12.scala
diff --git a/tests/run/erased-13.check b/tests/invalid/run/erased-13.check
similarity index 100%
rename from tests/run/erased-13.check
rename to tests/invalid/run/erased-13.check
diff --git a/tests/run/erased-13.scala b/tests/invalid/run/erased-13.scala
similarity index 100%
rename from tests/run/erased-13.scala
rename to tests/invalid/run/erased-13.scala
diff --git a/tests/run/erased-14.check b/tests/invalid/run/erased-14.check
similarity index 100%
rename from tests/run/erased-14.check
rename to tests/invalid/run/erased-14.check
diff --git a/tests/run/erased-14.scala b/tests/invalid/run/erased-14.scala
similarity index 100%
rename from tests/run/erased-14.scala
rename to tests/invalid/run/erased-14.scala
diff --git a/tests/run/erased-16.check b/tests/invalid/run/erased-16.check
similarity index 100%
rename from tests/run/erased-16.check
rename to tests/invalid/run/erased-16.check
diff --git a/tests/run/erased-16.scala b/tests/invalid/run/erased-16.scala
similarity index 100%
rename from tests/run/erased-16.scala
rename to tests/invalid/run/erased-16.scala
diff --git a/tests/run/erased-17.check b/tests/invalid/run/erased-17.check
similarity index 100%
rename from tests/run/erased-17.check
rename to tests/invalid/run/erased-17.check
diff --git a/tests/run/erased-17.scala b/tests/invalid/run/erased-17.scala
similarity index 100%
rename from tests/run/erased-17.scala
rename to tests/invalid/run/erased-17.scala
diff --git a/tests/run/erased-22.check b/tests/invalid/run/erased-22.check
similarity index 100%
rename from tests/run/erased-22.check
rename to tests/invalid/run/erased-22.check
diff --git a/tests/run/erased-22.scala b/tests/invalid/run/erased-22.scala
similarity index 100%
rename from tests/run/erased-22.scala
rename to tests/invalid/run/erased-22.scala
diff --git a/tests/run/erased-27.check b/tests/invalid/run/erased-27.check
similarity index 100%
rename from tests/run/erased-27.check
rename to tests/invalid/run/erased-27.check
diff --git a/tests/run/erased-27.scala b/tests/invalid/run/erased-27.scala
similarity index 100%
rename from tests/run/erased-27.scala
rename to tests/invalid/run/erased-27.scala
diff --git a/tests/run/erased-28.check b/tests/invalid/run/erased-28.check
similarity index 100%
rename from tests/run/erased-28.check
rename to tests/invalid/run/erased-28.check
diff --git a/tests/run/erased-28.scala b/tests/invalid/run/erased-28.scala
similarity index 100%
rename from tests/run/erased-28.scala
rename to tests/invalid/run/erased-28.scala
diff --git a/tests/run/erased-3.check b/tests/invalid/run/erased-3.check
similarity index 100%
rename from tests/run/erased-3.check
rename to tests/invalid/run/erased-3.check
diff --git a/tests/run/erased-3.scala b/tests/invalid/run/erased-3.scala
similarity index 100%
rename from tests/run/erased-3.scala
rename to tests/invalid/run/erased-3.scala
diff --git a/tests/run/erased-4.check b/tests/invalid/run/erased-4.check
similarity index 100%
rename from tests/run/erased-4.check
rename to tests/invalid/run/erased-4.check
diff --git a/tests/run/erased-4.scala b/tests/invalid/run/erased-4.scala
similarity index 100%
rename from tests/run/erased-4.scala
rename to tests/invalid/run/erased-4.scala
diff --git a/tests/run/erased-5.check b/tests/invalid/run/erased-5.check
similarity index 100%
rename from tests/run/erased-5.check
rename to tests/invalid/run/erased-5.check
diff --git a/tests/run/erased-5.scala b/tests/invalid/run/erased-5.scala
similarity index 100%
rename from tests/run/erased-5.scala
rename to tests/invalid/run/erased-5.scala
diff --git a/tests/run/erased-6.check b/tests/invalid/run/erased-6.check
similarity index 100%
rename from tests/run/erased-6.check
rename to tests/invalid/run/erased-6.check
diff --git a/tests/run/erased-6.scala b/tests/invalid/run/erased-6.scala
similarity index 100%
rename from tests/run/erased-6.scala
rename to tests/invalid/run/erased-6.scala
diff --git a/tests/run/erased-8.check b/tests/invalid/run/erased-8.check
similarity index 100%
rename from tests/run/erased-8.check
rename to tests/invalid/run/erased-8.check
diff --git a/tests/run/erased-8.scala b/tests/invalid/run/erased-8.scala
similarity index 100%
rename from tests/run/erased-8.scala
rename to tests/invalid/run/erased-8.scala
diff --git a/tests/run/erased-9.check b/tests/invalid/run/erased-9.check
similarity index 100%
rename from tests/run/erased-9.check
rename to tests/invalid/run/erased-9.check
diff --git a/tests/run/erased-9.scala b/tests/invalid/run/erased-9.scala
similarity index 100%
rename from tests/run/erased-9.scala
rename to tests/invalid/run/erased-9.scala
diff --git a/tests/run/erased-class-are-erased.check b/tests/invalid/run/erased-class-are-erased.check
similarity index 100%
rename from tests/run/erased-class-are-erased.check
rename to tests/invalid/run/erased-class-are-erased.check
diff --git a/tests/run/erased-class-are-erased.scala b/tests/invalid/run/erased-class-are-erased.scala
similarity index 100%
rename from tests/run/erased-class-are-erased.scala
rename to tests/invalid/run/erased-class-are-erased.scala
diff --git a/tests/run/erased-frameless.check b/tests/invalid/run/erased-frameless.check
similarity index 100%
rename from tests/run/erased-frameless.check
rename to tests/invalid/run/erased-frameless.check
diff --git a/tests/run/erased-frameless.scala b/tests/invalid/run/erased-frameless.scala
similarity index 88%
rename from tests/run/erased-frameless.scala
rename to tests/invalid/run/erased-frameless.scala
index fe654639492a..a366e705840c 100644
--- a/tests/run/erased-frameless.scala
+++ b/tests/invalid/run/erased-frameless.scala
@@ -28,7 +28,7 @@ trait Dataset[T] {
   // Use c.label to do an untyped select on actual Spark Dataset, and
   // cast the result to TypedDataset[A]
 
-  def col[S <: String, A](s: S) (using erased ev: Exists[T, s.type, A]) =
+  inline def col[S <: String, A](s: S) (using erased ev: Exists[T, s.type, A]) =
     new Column[T, A](s) // ev is only here to check than this is safe, it's never used at runtime!
 
   def collect(): Vector[T]
@@ -71,17 +71,17 @@ case class Column[T, A](label: String)
 trait Exists[T, K, V]
 
 object Exists {
-  implicit def derive[T, H <: HList, K, V](implicit g: LabelledGeneric[T] { type Repr = H }, s: Selector[H, K, V]): Exists[T, K, V] = {
+  inline implicit def derive[T, H <: HList, K, V](implicit g: LabelledGeneric[T] { type Repr = H }, s: Selector[H, K, V]): Exists[T, K, V] = {
     println("Exists.derive")
     null
   }
 
-  implicit def caseFound[T <: HList, K <: String, V]: Selector[R[K, V] :: T, K, V] = {
+  inline implicit def caseFound[T <: HList, K <: String, V]: Selector[R[K, V] :: T, K, V] = {
     println("Selector.caseFound")
     null
   }
 
-  implicit def caseRecur[H, T <: HList, K <: String, V](implicit i: Selector[T, K, V]): Selector[H :: T, K, V] = {
+  inline implicit def caseRecur[H, T <: HList, K <: String, V](implicit i: Selector[T, K, V]): Selector[H :: T, K, V] = {
     println("Selector.caseRecur")
     null
   }
diff --git a/tests/run/erased-select-prefix.check b/tests/invalid/run/erased-select-prefix.check
similarity index 100%
rename from tests/run/erased-select-prefix.check
rename to tests/invalid/run/erased-select-prefix.check
diff --git a/tests/run/erased-select-prefix.scala b/tests/invalid/run/erased-select-prefix.scala
similarity index 77%
rename from tests/run/erased-select-prefix.scala
rename to tests/invalid/run/erased-select-prefix.scala
index b877a0d209d7..06ed46d5ccce 100644
--- a/tests/run/erased-select-prefix.scala
+++ b/tests/invalid/run/erased-select-prefix.scala
@@ -29,9 +29,9 @@ object Test {
 
   def bar(erased i: Int): Unit = ()
 
-  erased def foo0: Int = 0
-  erased def foo1(): Int = 1
-  erased def foo2[T]: Int = 2
-  erased def foo3[T](): Int = 3
+  inline def foo0: Int = 0
+  inline def foo1(): Int = 1
+  inline def foo2[T]: Int = 2
+  inline def foo3[T](): Int = 3
 
 }
diff --git a/tests/run/erased-value-class.check b/tests/invalid/run/erased-value-class.check
similarity index 100%
rename from tests/run/erased-value-class.check
rename to tests/invalid/run/erased-value-class.check
diff --git a/tests/run/erased-value-class.scala b/tests/invalid/run/erased-value-class.scala
similarity index 100%
rename from tests/run/erased-value-class.scala
rename to tests/invalid/run/erased-value-class.scala
diff --git a/tests/run/polymorphic-erased-functions.scala b/tests/invalid/run/polymorphic-erased-functions.scala
similarity index 100%
rename from tests/run/polymorphic-erased-functions.scala
rename to tests/invalid/run/polymorphic-erased-functions.scala
diff --git a/tests/neg/erased-6.scala b/tests/neg/erased-6.scala
index 4585ab876b3d..76fa1b937f00 100644
--- a/tests/neg/erased-6.scala
+++ b/tests/neg/erased-6.scala
@@ -1,7 +1,7 @@
 //> using options -language:experimental.erasedDefinitions
 
 object Test {
-  erased def foo: Foo = new Foo
+  erased val foo: Foo = new Foo  // error, Foo is not noInits
   foo.x() // error
   foo.y // error
   foo.z // error
diff --git a/tests/neg/erased-assign.scala b/tests/neg/erased-assign.scala
index 5026ca3f1856..61c8802e576e 100644
--- a/tests/neg/erased-assign.scala
+++ b/tests/neg/erased-assign.scala
@@ -4,7 +4,7 @@ object Test {
   var i: Int = 1
   def foo(erased a: Int): Int = {
     i = a // error
-    erased def r = {
+    inline def r = {
       i = a
       ()
     }
diff --git a/tests/neg/erased-class.scala b/tests/neg/erased-class.scala
index 96a1c8769bb1..aede15b9ef70 100644
--- a/tests/neg/erased-class.scala
+++ b/tests/neg/erased-class.scala
@@ -4,7 +4,7 @@ erased class AA
 erased class BB extends AA // ok
 
 @main def Test =
-  val f1: Array[AA] = compiletime.erasedValue // error // error
-  def f2(x: Int): Array[AA] = compiletime.erasedValue // error // error
-  def bar: AA = compiletime.erasedValue  // ok
-  val baz: AA = compiletime.erasedValue // ok
+  val f1: Array[AA] = caps.unsafe.unsafeErasedValue // error // error
+  def f2(x: Int): Array[AA] = caps.unsafe.unsafeErasedValue // error // error
+  def bar: AA = caps.unsafe.unsafeErasedValue  // ok
+  val baz: AA = caps.unsafe.unsafeErasedValue // ok
diff --git a/tests/neg/erased-path.scala b/tests/neg/erased-path.scala
index ece90e563483..6666165d5cc6 100644
--- a/tests/neg/erased-path.scala
+++ b/tests/neg/erased-path.scala
@@ -6,6 +6,6 @@ trait Obj {
   erased val s: Sys
   lazy val t: Sys
 
-  type S = s.X  // error: not a legal path, since nonfinal
+  type S = s.X  // now OK, was error: not a legal path, since nonfinal
   type T = t.X  // error: not a legal path, since nonfinal
 }
\ No newline at end of file
diff --git a/tests/neg/erasedValueb.check b/tests/neg/erasedValueb.check
new file mode 100644
index 000000000000..f5765064a036
--- /dev/null
+++ b/tests/neg/erasedValueb.check
@@ -0,0 +1,10 @@
+-- Error: tests/neg/erasedValueb.scala:7:7 -----------------------------------------------------------------------------
+7 |  foo0(erasedValue[Int]) // error
+  |       ^^^^^^^^^^^
+  |       method erasedValue is declared as `erased`, but is in fact used
+-- [E216] Type Error: tests/neg/erasedValueb.scala:8:18 ----------------------------------------------------------------
+8 |  foo1(erasedValue[Int]) // error
+  |       ^^^^^^^^^^^^^^^^
+  |       argument to an erased parameter fails to be a pure expression
+  |
+  | longer explanation available when compiling with `-explain`
diff --git a/tests/neg/erasedValueb.scala b/tests/neg/erasedValueb.scala
index 5c1f1d359e93..a25cf66ec3cb 100644
--- a/tests/neg/erasedValueb.scala
+++ b/tests/neg/erasedValueb.scala
@@ -5,5 +5,5 @@ object Test {
   def foo0(a: Int): Int = 3
   def foo1(erased a: Int): Int = 3
   foo0(erasedValue[Int]) // error
-  foo1(erasedValue[Int])
+  foo1(erasedValue[Int]) // error
 }
diff --git a/tests/neg/experimental-imports.scala b/tests/neg/experimental-imports.scala
index e3a91be45f08..10e655ddf3b2 100644
--- a/tests/neg/experimental-imports.scala
+++ b/tests/neg/experimental-imports.scala
@@ -8,14 +8,14 @@ object Object1:
   import language.experimental.namedTypeArguments
   import language.experimental.genericNumberLiterals
   import language.experimental.erasedDefinitions
-  erased def f = 1
+  erased val f = 1
 
 object Object2:
   import language.experimental.fewerBraces // error
   import language.experimental.namedTypeArguments // error
   import language.experimental.genericNumberLiterals // error
   import language.experimental.erasedDefinitions // error
-  erased def f = 1
+  erased val f = 1
 
 @experimental
 object Class1:
@@ -23,14 +23,14 @@ object Class1:
   import language.experimental.namedTypeArguments
   import language.experimental.genericNumberLiterals
   import language.experimental.erasedDefinitions
-  erased def f = 1
+  erased val f = 1
 
 object Class2:
   import language.experimental.fewerBraces // error
   import language.experimental.namedTypeArguments // error
   import language.experimental.genericNumberLiterals // error
   import language.experimental.erasedDefinitions // error
-  erased def f = 1
+  erased val f = 1
 
 @experimental
 def fun1 =
@@ -38,11 +38,11 @@ def fun1 =
   import language.experimental.namedTypeArguments
   import language.experimental.genericNumberLiterals
   import language.experimental.erasedDefinitions
-  erased def f = 1
+  erased val f = 1
 
 def fun2 =
   import language.experimental.fewerBraces // error
   import language.experimental.namedTypeArguments // error
   import language.experimental.genericNumberLiterals // error
   import language.experimental.erasedDefinitions // error
-  erased def f = 1
+  erased val f = 1
diff --git a/tests/neg/experimental.scala b/tests/neg/experimental.scala
index f35a7ca19d7f..583a8c5aa183 100644
--- a/tests/neg/experimental.scala
+++ b/tests/neg/experimental.scala
@@ -13,7 +13,7 @@ class Test1 {
   import scala.compiletime.erasedValue
   type UnivEq[A]
   object UnivEq:
-    erased def force[A]: UnivEq[A] = erasedValue
+    inline def force[A]: UnivEq[A] = erasedValue
     extension [A](erased proof: UnivEq[A])
       inline def univEq(a: A, b: A): Boolean =
         a == b
diff --git a/tests/neg/i23406.check b/tests/neg/i23406.check
new file mode 100644
index 000000000000..a9ca83c9a8b3
--- /dev/null
+++ b/tests/neg/i23406.check
@@ -0,0 +1,40 @@
+-- Error: tests/neg/i23406.scala:18:7 ----------------------------------------------------------------------------------
+18 |  funny[String]  // error
+   |  ^^^^^^^^^^^^^
+   |  value x is unusable in method Test because it refers to an erased expression
+   |  in the selector of an inline match that reduces to
+   |
+   |  {
+   |    erased val $scrutinee1: String = compiletime.package$package.erasedValue[String]
+   |    erased val x: String = $scrutinee1
+   |    {
+   |      x:String
+   |    }
+   |  }
+   |--------------------------------------------------------------------------------------------------------------------
+   |Inline stack trace
+   |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+   |This location contains code that was inlined from i23406.scala:7
+ 7 |    case x: String => x
+   |                      ^
+    --------------------------------------------------------------------------------------------------------------------
+-- Error: tests/neg/i23406.scala:19:9 ----------------------------------------------------------------------------------
+19 |  problem[String] // error
+   |  ^^^^^^^^^^^^^^^
+   |  value x is unusable in method Test because it refers to an erased expression
+   |  in the selector of an inline match that reduces to
+   |
+   |  {
+   |    erased val $scrutinee2: String = compiletime.package$package.erasedValue[String]
+   |    erased val x: String = $scrutinee2
+   |    {
+   |      foo(x)
+   |    }
+   |  }
+   |--------------------------------------------------------------------------------------------------------------------
+   |Inline stack trace
+   |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+   |This location contains code that was inlined from i23406.scala:11
+11 |    case x: String => foo(x)
+   |                          ^
+    --------------------------------------------------------------------------------------------------------------------
diff --git a/tests/neg/i23406.scala b/tests/neg/i23406.scala
new file mode 100644
index 000000000000..ffebf0e78701
--- /dev/null
+++ b/tests/neg/i23406.scala
@@ -0,0 +1,20 @@
+import language.experimental.erasedDefinitions
+
+def foo(erased x: String): String = ""
+
+inline def funny[T]: String =
+  inline compiletime.erasedValue[T] match
+    case x: String => x
+
+inline def problem[T]: String =
+  inline compiletime.erasedValue[T] match
+    case x: String => foo(x)
+
+inline def ok[T]: String =
+  inline compiletime.erasedValue[T] match
+    case x: String => "hi"
+
+def Test =
+  funny[String]  // error
+  problem[String] // error
+  ok[String]
diff --git a/tests/neg/i4060.scala b/tests/neg/i4060.scala
index bd16ed867966..b85c1190cc3e 100644
--- a/tests/neg/i4060.scala
+++ b/tests/neg/i4060.scala
@@ -6,7 +6,7 @@ object App {
   trait A { type L >: Any}
   def upcast(erased a: A)(x: Any): a.L = x
   erased val p: A { type L <: Nothing } = p
-  def coerce(x: Any): Int = upcast(p)(x) // error
+  def coerce(x: Any): Int = upcast(p)(x) // ok?
 
   def coerceInline(x: Any): Int = upcast(compiletime.erasedValue[A {type L <: Nothing}])(x) // error
 
@@ -14,7 +14,7 @@ object App {
   def upcast_dep_parameter(erased a: B)(x: a.L) : Int = x
   erased val q : B { type L >: Any } = compiletime.erasedValue
 
-  def coerceInlineWithB(x: Any): Int = upcast_dep_parameter(q)(x) // error
+  def coerceInlineWithB(x: Any): Int = upcast_dep_parameter(q)(x) // ok?
 
   def main(args: Array[String]): Unit = {
     println(coerce("Uh oh!"))
diff --git a/tests/neg/magic-canthrow.scala b/tests/neg/magic-canthrow.scala
new file mode 100644
index 000000000000..ceca68fd233a
--- /dev/null
+++ b/tests/neg/magic-canthrow.scala
@@ -0,0 +1,11 @@
+import language.experimental.erasedDefinitions
+import java.io.IOException
+
+class CanThrow[-E <: Exception]
+
+def foo[E <: Exception](e: E)(using erased CanThrow[E]): Nothing = throw e
+
+erased def magic[E]: E = magic  // error
+
+def Test = foo(new IOException)(using magic)
+
diff --git a/tests/neg/typeclass-derivation2.scala b/tests/neg/typeclass-derivation2.scala
index eca11fb326ed..ba89fb4c39c8 100644
--- a/tests/neg/typeclass-derivation2.scala
+++ b/tests/neg/typeclass-derivation2.scala
@@ -119,7 +119,7 @@ object TypeLevel {
   type Subtype[t] = Type[_, t]
   type Supertype[t] = Type[t, _]
   type Exactly[t] = Type[t, t]
-  erased def typeOf[T]: Type[T, T] = compiletime.erasedValue
+  inline def typeOf[T]: Type[T, T] = compiletime.erasedValue
 }
 
 // An algebraic datatype
diff --git a/tests/new/test.scala b/tests/new/test.scala
index d350e15a8c9f..dc0b40d6a755 100644
--- a/tests/new/test.scala
+++ b/tests/new/test.scala
@@ -1,15 +1,12 @@
+import java.io.IOException
 
-package foo
-
-package object bar:
-  opaque type O[X] >: X = X
-
-class Test:
-  import bar.O
-
-  val x = "abc"
-  val y: O[String] = x
-  //val z: String = y
+class CanThrow[-E <: Exception]
 
+def foo[E <: Exception](e: E)(using erased CanThrow[E]): Nothing = throw e
 
+erased def magic[E]: E = magic // error
+inline def moreMagic[E]: E = moreMagic
 
+def Test =
+  foo(new IOException)(using magic)
+  foo(new IOException)(using moreMagic) // should be error
diff --git a/tests/pending/neg/erased-impure.check b/tests/pending/neg/erased-impure.check
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/tests/pending/neg/erased-impure.scala b/tests/pending/neg/erased-impure.scala
new file mode 100644
index 000000000000..8dd668bbc529
--- /dev/null
+++ b/tests/pending/neg/erased-impure.scala
@@ -0,0 +1,44 @@
+//> using options -explain
+import language.experimental.erasedDefinitions
+import java.io.IOException
+import caps.unsafe.unsafeErasedValue
+
+class CanThrow[-E <: Exception]
+
+def foo[E <: Exception](e: E)(using erased CanThrow[E]): Nothing = throw e
+
+erased val magic1: IOException = ???  // error
+erased val magic2: IOException = compiletime.erasedValue[IOException]  // error
+erased val magic3: IOException = null.asInstanceOf[IOException]  // error
+
+inline def inlineId[T](x: T) = x
+
+class C()
+
+def testPure[T](erased x: T): Unit = ()
+
+case class Pair[A, B](x: A, y: B)
+object Pair:
+  def apply(x: Int): Pair2[Int, Int] =
+    println("Pair2")
+    Pair2(x, x + 1)
+
+case class Box[A](x: A):
+  println(x)
+
+def Test =
+  foo(new IOException)(using ???)  // error
+  foo(new IOException)(using inlineId(???))  // error
+
+  testPure(C()) // OK
+  testPure(inlineId(C())) // OK
+  testPure(identity(C())) // error, identity is not an inline function
+
+  testPure(Pair(unsafeErasedValue[Int], unsafeErasedValue[String])) // OK
+  testPure(Pair(unsafeErasedValue[Int])) // error
+  testPure(Box(unsafeErasedValue[Int])) // error
+
+
+
+
+
diff --git a/tests/pos-custom-args/captures/try.scala b/tests/pos-custom-args/captures/try.scala
index 5faabecc411c..c88c842babc5 100644
--- a/tests/pos-custom-args/captures/try.scala
+++ b/tests/pos-custom-args/captures/try.scala
@@ -14,7 +14,7 @@ def foo(x: Boolean): Int throws Fail =
   if x then 1 else raise(Fail())
 
 def handle[E <: Exception, R](op: (erased CanThrow[E]) -> R)(handler: E -> R): R =
-  erased val x: CanThrow[E] = ??? : CanThrow[E]
+  erased val x = caps.unsafe.unsafeErasedValue[CanThrow[E]]
   try op(x)
   catch case ex: E => handler(ex)
 
diff --git a/tests/neg/erased-24.scala b/tests/pos/erased-24.scala
similarity index 77%
rename from tests/neg/erased-24.scala
rename to tests/pos/erased-24.scala
index bf2f1d21435e..410a1900a1c1 100644
--- a/tests/neg/erased-24.scala
+++ b/tests/pos/erased-24.scala
@@ -12,8 +12,8 @@ object Test {
     null.asInstanceOf[foo.X] // ok
   }
 
-  def fun2(erased foo: Foo)(erased bar: foo.B): bar.X = { // error
-    null.asInstanceOf[bar.X] // error
+  def fun2(erased foo: Foo)(erased bar: foo.B): bar.X = { // was error
+    null.asInstanceOf[bar.X] // was error
   }
 }
 
diff --git a/tests/pos/erased-asInstanceOf.scala b/tests/pos/erased-asInstanceOf.scala
index 692ff3a16b05..7029c298452c 100644
--- a/tests/pos/erased-asInstanceOf.scala
+++ b/tests/pos/erased-asInstanceOf.scala
@@ -11,7 +11,7 @@ object Test {
 
     val ds: Dataset = ???
 
-    lazy val collD = new Column
+    val collD = new Column
 
     ds.select(collD)
 
diff --git a/tests/pos/erased-conforms.scala b/tests/pos/erased-conforms.scala
index 426490d5a53a..311b244b9872 100644
--- a/tests/pos/erased-conforms.scala
+++ b/tests/pos/erased-conforms.scala
@@ -5,7 +5,7 @@ erased class <::<[-From, +To] extends ErasedTerm
 
 erased class =::=[From, To] extends (From <::< To)
 
-erased given [X] => (X =::= X) = scala.compiletime.erasedValue
+inline given [X] => (X =::= X) = scala.caps.unsafe.unsafeErasedValue
 
 extension [From](x: From)
   inline def cast[To](using From <::< To): To = x.asInstanceOf[To] // Safe cast because we know `From <:< To`
diff --git a/tests/neg/erased-pathdep-1.scala b/tests/pos/erased-pathdep-1.scala
similarity index 67%
rename from tests/neg/erased-pathdep-1.scala
rename to tests/pos/erased-pathdep-1.scala
index 422ceb5e37fe..e696c48df328 100644
--- a/tests/neg/erased-pathdep-1.scala
+++ b/tests/pos/erased-pathdep-1.scala
@@ -1,16 +1,14 @@
 //> using options -language:experimental.erasedDefinitions
 
-// Could become a neg test if we had totality checking for erased arguments
-
 object Test {
 
   fun1(new Bar)
   val _ = fun2(new Bar)
   val _ = fun3(new Bar)
 
-  def fun1[F >: Bar <: Foo](erased f: F): f.X = null.asInstanceOf[f.X] // error // error
-  def fun2[F >: Bar <: Foo](erased f: F)(erased bar: f.B): f.B = null.asInstanceOf[f.B] // error // error // error
-  def fun3[F >: Bar <: Foo](erased f: F)(erased b: f.B): b.X = null.asInstanceOf[b.X] // error // error // error
+  def fun1[F >: Bar <: Foo](erased f: F): f.X = null.asInstanceOf[f.X]
+  def fun2[F >: Bar <: Foo](erased f: F)(erased bar: f.B): f.B = null.asInstanceOf[f.B]
+  def fun3[F >: Bar <: Foo](erased f: F)(erased b: f.B): b.X = null.asInstanceOf[b.X]
 }
 
 class Foo {
diff --git a/tests/neg/erased-pathdep-2.scala b/tests/pos/erased-pathdep-2.scala
similarity index 81%
rename from tests/neg/erased-pathdep-2.scala
rename to tests/pos/erased-pathdep-2.scala
index 0b50acbf3b30..8c9f7b414a98 100644
--- a/tests/neg/erased-pathdep-2.scala
+++ b/tests/pos/erased-pathdep-2.scala
@@ -7,8 +7,8 @@ object Test {
   type F >: Bar <: Foo
 
   class A(erased val f: F) {
-    type F1 <: f.X // error
-    type F2[Z <: f.X] // error
+    type F1 <: f.X // was error
+    type F2[Z <: f.X] // was error
   }
 
 }
diff --git a/tests/pos/erased-pure.scala b/tests/pos/erased-pure.scala
index 9d2b54ac02b4..e62563669e66 100644
--- a/tests/pos/erased-pure.scala
+++ b/tests/pos/erased-pure.scala
@@ -1,4 +1,5 @@
 import language.experimental.erasedDefinitions
+import caps.unsafe.unsafeErasedValue
 
 inline def id[T](x: T) = x
 
@@ -8,6 +9,7 @@ def foo[T](erased x: T): Unit = ()
 
 class Pair[A, B](x: A, y: B)
 
+case class Pair2[A, B](x: A, y: B)
 
 def Test =
   foo(C())
@@ -17,7 +19,8 @@ def Test =
   foo(Pair(C(), "hello" + "world"))
   foo(id(Pair(id(C()), id("hello" + "world"))))
 
-
-
+  //erased val x1 = Pair(unsafeErasedValue[Int], unsafeErasedValue[String])
+  //erased val x2 = Pair2(unsafeErasedValue[Int], unsafeErasedValue[String])
+  erased val x3 = Tuple2(unsafeErasedValue[Int], unsafeErasedValue[String])
 
 
diff --git a/tests/neg/erased-singleton.scala b/tests/pos/erased-singleton.scala
similarity index 67%
rename from tests/neg/erased-singleton.scala
rename to tests/pos/erased-singleton.scala
index 5ffa78e24b07..f7ad5165ec0a 100644
--- a/tests/neg/erased-singleton.scala
+++ b/tests/pos/erased-singleton.scala
@@ -5,5 +5,5 @@ trait Sys
 trait Obj {
   erased val s: Sys
 
-  type S = s.type  // error: non final
+  type S = s.type  // now OK, was error: non final
 }
diff --git a/tests/pos/expeimental-flag-with-lang-feature.scala b/tests/pos/expeimental-flag-with-lang-feature.scala
deleted file mode 100644
index 96069c332e02..000000000000
--- a/tests/pos/expeimental-flag-with-lang-feature.scala
+++ /dev/null
@@ -1,10 +0,0 @@
-//> using options -experimental
-
-import scala.language.experimental.erasedDefinitions
-import scala.language.experimental.namedTypeArguments
-
-erased def erasedFun(erased x: Int): Int = x
-
-def namedTypeArgumentsFun[T, U]: Int =
-  namedTypeArgumentsFun[T = Int, U = Int]
-  namedTypeArgumentsFun[U = Int, T = Int]
diff --git a/tests/pos/experimental-imports-top.scala b/tests/pos/experimental-imports-top.scala
index 9ba2b5cd2c99..595caac66fe7 100644
--- a/tests/pos/experimental-imports-top.scala
+++ b/tests/pos/experimental-imports-top.scala
@@ -4,4 +4,4 @@ import language.experimental.erasedDefinitions
 import annotation.experimental
 
 @experimental
-erased def f = 1
+erased val f = 1
diff --git a/tests/pos/experimentalErased.scala b/tests/pos/experimentalErased.scala
index 358c134c714a..4a504e3d8a80 100644
--- a/tests/pos/experimentalErased.scala
+++ b/tests/pos/experimentalErased.scala
@@ -6,11 +6,6 @@ erased class Foo
 
 erased class Bar
 
-@experimental
-erased def foo = 2
-
-erased def bar = 2
-
 @experimental
 erased val foo2 = 2
 
diff --git a/tests/pos/i11864.scala b/tests/pos/i11864.scala
index ba43336e13ca..0301b50d7021 100644
--- a/tests/pos/i11864.scala
+++ b/tests/pos/i11864.scala
@@ -40,7 +40,7 @@ final class CallbackTo[+A] {
 object CallbackTo {
 
   type MapGuard[A] = { type Out = A }
-  erased given MapGuard: [A] => MapGuard[A] = compiletime.erasedValue
+  inline given MapGuard: [A] => MapGuard[A] = caps.unsafe.unsafeErasedValue
 
   def traverse[A, B](ta: List[A]): CallbackTo[List[B]] =
     val x: CallbackTo[List[A] => List[B]] = ???
diff --git a/tests/pos/i11896.scala b/tests/pos/i11896.scala
index 49e5307f1a49..a4816eb5ad18 100644
--- a/tests/pos/i11896.scala
+++ b/tests/pos/i11896.scala
@@ -1,7 +1,7 @@
 import scala.language.experimental.erasedDefinitions
 
 type X
-erased def x: X = compiletime.erasedValue
+inline def x: X = caps.unsafe.unsafeErasedValue
 
 def foo(using erased X): Unit = ()
 
diff --git a/tests/pos/i5938.scala b/tests/pos/i5938.scala
index 17a20dcd0f1f..f392de153b4c 100644
--- a/tests/pos/i5938.scala
+++ b/tests/pos/i5938.scala
@@ -1,7 +1,6 @@
 import scala.language.experimental.erasedDefinitions
 
 import compiletime.summonFrom
-import compiletime.erasedValue
 
 trait Link[T, A]
 
@@ -15,7 +14,7 @@ transparent inline def link[T] =
 
 class Foo
 object Foo {
-  erased implicit val barLink: Link[Foo, Bar.type] = erasedValue
+  erased implicit val barLink: Link[Foo, Bar.type] = caps.unsafe.unsafeErasedValue
 }
 
 implicit object Bar {
diff --git a/tests/pos/i6419.scala b/tests/pos/i6419.scala
index 550922f48d76..44136d9e48a3 100644
--- a/tests/pos/i6419.scala
+++ b/tests/pos/i6419.scala
@@ -9,8 +9,4 @@ class Foo {
   inline def bar: Unit = {
     foo
   }
-
-  erased def baz: Unit = {
-    foo
-  }
 }
diff --git a/tests/pos/i7741.scala b/tests/pos/i7741.scala
index af9912915cc0..981789f14e2a 100644
--- a/tests/pos/i7741.scala
+++ b/tests/pos/i7741.scala
@@ -3,9 +3,6 @@ import scala.language.experimental.erasedDefinitions
 class A1 {
     @native private def a: Unit
 }
-trait A2 {
-    erased def i(erased a: Int): Int
-}
 trait A3 {
     erased val a: Int
 }
\ No newline at end of file
diff --git a/tests/pos/i7868.scala b/tests/pos/i7868.scala
deleted file mode 100644
index fa31bd131b0c..000000000000
--- a/tests/pos/i7868.scala
+++ /dev/null
@@ -1,42 +0,0 @@
-//> using options -language:experimental.erasedDefinitions
-
-import language.experimental.namedTypeArguments
-import scala.compiletime.*
-import scala.compiletime.ops.int.*
-
-final case class Coproduct[+Set, +Value, Index <: Int](value: Value & Set, index: Index)
-
-object Coproduct {
-  opaque type +:[+A, +B] = A | B
-
-  trait At[+Set, -Value, Index <: Int] {
-    def cast: Value <:< Set
-  }
-
-  object At {
-
-    given atHead: [Head, Tail] => At[Head +: Tail, Head, 0]:
-      def cast: Head <:< Head +: Tail = summon[Head <:< Head +: Tail]
-
-    given atTail[Head, Tail, Value, NextIndex <: Int]
-          (using atNext: At[Tail, Value, NextIndex])
-      : At[Head +: Tail, Value, S[NextIndex]] with
-      val cast: Value <:< Head +: Tail = atNext.cast
-
-    given [A] => A => (() => A) = { () => summon[A] }
-  }
-
-  def upCast[A, B](a: A)(using erased evidence: (A <:< B) ): B = a.asInstanceOf[B]
-
-  def from[Set, Value, Index <: Int](value: Value)(using erased at: At[Set, Value, Index]) : ValueOf[Index] ?=> Coproduct[Set, Value, Index] = {
-    Coproduct[Set, Value, Index](upCast(value: Value)(using at.cast.liftCo[[X] =>> Value & X]), valueOf[Index])
-  }
-
-}
-
-object Test extends App {
-  import Coproduct.*
-
-  // Error: No singleton value available for scala.compiletime.ops.int.S[scala.compiletime.ops.int.S[(0 : Int)]].
-  val c = from[Set = Int +: String +: Seq[Double] +: Nothing](Nil)
-}
diff --git a/tests/pos/inline-match-gadt.scala b/tests/pos/inline-match-gadt.scala
index cf2aae00b402..7c966f33bf48 100644
--- a/tests/pos/inline-match-gadt.scala
+++ b/tests/pos/inline-match-gadt.scala
@@ -2,7 +2,7 @@ import scala.language.experimental.erasedDefinitions
 
 object `inline-match-gadt` {
   class Exactly[T]
-  erased def exactType[T]: Exactly[T] = compiletime.erasedValue
+  inline def exactType[T]: Exactly[T] = compiletime.erasedValue
 
   inline def foo[T](t: T): T =
     inline exactType[T] match {
diff --git a/tests/pos/matchtype.scala b/tests/pos/matchtype.scala
index 21c074deafd7..90d8f0dc6400 100644
--- a/tests/pos/matchtype.scala
+++ b/tests/pos/matchtype.scala
@@ -1,5 +1,5 @@
 import scala.language.experimental.erasedDefinitions
-import compiletime.erasedValue
+import caps.unsafe.unsafeErasedValue as erasedValue
 import compiletime.ops.int.S
 object Test {
   type T[X] = X match {
diff --git a/tests/pos/phantom-Eq.scala b/tests/pos/phantom-Eq.scala
index d844c4b110c6..f3a4af02a186 100644
--- a/tests/pos/phantom-Eq.scala
+++ b/tests/pos/phantom-Eq.scala
@@ -16,18 +16,19 @@ object PhantomEq {
 
 object EqUtil {
 
-  type PhantomEq[-L, -R]
+  class PhantomEq[-L, -R]
   type PhantomEqEq[T] = PhantomEq[T, T]
+  erased val phantomEq = PhantomEq[Any, Any]()
 
   extension [T](x: T)
     def ===[U](y: U)(using erased PhantomEq[T, U]) = x.equals(y)
 
-  erased given eqString: PhantomEqEq[String] = compiletime.erasedValue
-  erased given eqInt: PhantomEqEq[Int]       = compiletime.erasedValue
-  erased given eqDouble: PhantomEqEq[Double] = compiletime.erasedValue
+  inline given eqString: PhantomEqEq[String] = phantomEq
+  inline given eqInt: PhantomEqEq[Int]       = phantomEq
+  inline given eqDouble: PhantomEqEq[Double] = phantomEq
 
-  erased given eqByteNum: PhantomEq[Byte, Number] = compiletime.erasedValue
-  erased given eqNumByte: PhantomEq[Number, Byte] = compiletime.erasedValue
+  inline given eqByteNum: PhantomEq[Byte, Number] = phantomEq
+  inline given eqNumByte: PhantomEq[Number, Byte] = phantomEq
 
-  erased given eqSeq: [T, U] => (erased PhantomEq[T, U]) => PhantomEq[Seq[T], Seq[U]] = compiletime.erasedValue
+  inline given eqSeq: [T, U] => (erased PhantomEq[T, U]) => PhantomEq[Seq[T], Seq[U]] = phantomEq
 }
diff --git a/tests/pos/phantom-Eq2/Phantom-Eq_1.scala b/tests/pos/phantom-Eq2/Phantom-Eq_1.scala
index b041a4a87efe..b5021a30b09b 100644
--- a/tests/pos/phantom-Eq2/Phantom-Eq_1.scala
+++ b/tests/pos/phantom-Eq2/Phantom-Eq_1.scala
@@ -1,19 +1,20 @@
 import scala.language.experimental.erasedDefinitions
+import scala.annotation.publicInBinary
 
 /* This is a version of ../pos/phantomEq.scala that tests phantom with separate compilation */
 object EqUtil {
 
-  final class PhantomEq[-L, -R] private[EqUtil]()
+  final class PhantomEq[-L, -R] @publicInBinary private[EqUtil]()
   type PhantomEqEq[T] = PhantomEq[T, T]
 
   extension [T](x: T)
     def ===[U] (y: U) (using erased PhantomEq[T, U]) = x.equals(y)
 
-  erased given eqString: PhantomEqEq[String] = new PhantomEq[String, String]
-  erased given eqInt: PhantomEqEq[Int]       = new PhantomEq[Int, Int]
-  erased given eqDouble: PhantomEqEq[Double] = new PhantomEq[Double, Double]
-  erased given eqByteNum: PhantomEq[Byte, Number] = new PhantomEq[Byte, Number]
-  erased given eqNumByte: PhantomEq[Number, Byte] = new PhantomEq[Number, Byte]
-  erased given eqSeq: [T, U] => (erased eq: PhantomEq[T, U]) => PhantomEq[Seq[T], Seq[U]] =
+  inline given eqString: PhantomEqEq[String] = new PhantomEq[String, String]
+  inline given eqInt: PhantomEqEq[Int]       = new PhantomEq[Int, Int]
+  inline given eqDouble: PhantomEqEq[Double] = new PhantomEq[Double, Double]
+  inline given eqByteNum: PhantomEq[Byte, Number] = new PhantomEq[Byte, Number]
+  inline given eqNumByte: PhantomEq[Number, Byte] = new PhantomEq[Number, Byte]
+  inline given eqSeq: [T, U] => (erased eq: PhantomEq[T, U]) => PhantomEq[Seq[T], Seq[U]] =
     new PhantomEq[Seq[T], Seq[U]]
 }
diff --git a/tests/pos/phantom-Evidence.scala b/tests/pos/phantom-Evidence.scala
index f56ce3b798ee..db39a7b4659e 100644
--- a/tests/pos/phantom-Evidence.scala
+++ b/tests/pos/phantom-Evidence.scala
@@ -1,4 +1,5 @@
 import scala.language.experimental.erasedDefinitions
+import annotation.publicInBinary
 
 /** In this implementation variant of =:= (called =::=) we erase all instantiations and definitions of =::= */
 object WithNormalState {
@@ -11,9 +12,9 @@ object WithNormalState {
   object Instance {
     def newInstance(): Instance[Off] = new Instance[Off]
   }
-  class Instance[S <: State] private {
-    def getOnInstance (using erased ev: S =::= Off): Instance[On] = new Instance[On] // phantom parameter ev is erased
-    def getOffInstance (using erased ev: S =::= On): Instance[Off] = new Instance[Off] // phantom parameter ev is erased
+  class Instance[S <: State] @publicInBinary private {
+    inline def getOnInstance (using erased ev: S =::= Off): Instance[On] = new Instance[On] // phantom parameter ev is erased
+    inline def getOffInstance (using erased ev: S =::= On): Instance[Off] = new Instance[Off] // phantom parameter ev is erased
   }
 
   def run() = {
@@ -26,5 +27,5 @@ object WithNormalState {
 
 object Utils {
   type =::=[From, To]
-  erased given tpEquals: [A] => (A =::= A) = compiletime.erasedValue
+  inline given tpEquals: [A] => (A =::= A) = caps.unsafe.unsafeErasedValue
 }
diff --git a/tests/run/erased-18.scala b/tests/run/erased-18.scala
index 46f7e44c7309..2e5275690ea2 100644
--- a/tests/run/erased-18.scala
+++ b/tests/run/erased-18.scala
@@ -11,8 +11,8 @@ object Test {
     )(foo)
   }
 
-  def foo = {
-    println("foo")
+  inline def foo = {
+    //println("foo")
     42
   }
 }
diff --git a/tests/run/erased-machine-state.scala b/tests/run/erased-machine-state.scala
index c84f1619366d..2431d34e9dfe 100644
--- a/tests/run/erased-machine-state.scala
+++ b/tests/run/erased-machine-state.scala
@@ -9,8 +9,7 @@ final class Off extends State
 @implicitNotFound("State must be Off")
 class IsOff[S <: State]
 object IsOff {
-  implicit def isOff: IsOff[Off] = {
-    println("isOff")
+  inline implicit def isOff: IsOff[Off] = {
     new IsOff[Off]
   }
 }
@@ -18,8 +17,7 @@ object IsOff {
 @implicitNotFound("State must be On")
 class IsOn[S <: State]
 object IsOn {
-  implicit def isOn: IsOn[On] = {
-    println("isOn")
+  inline implicit def isOn: IsOn[On] = {
     new IsOn[On]
   }
 }
diff --git a/tests/run/erased-poly-ref.scala b/tests/run/erased-poly-ref.scala
index 59badb71255d..975a576cc15b 100644
--- a/tests/run/erased-poly-ref.scala
+++ b/tests/run/erased-poly-ref.scala
@@ -8,10 +8,9 @@ object Test {
 
   def fun(erased a: Int): Unit = println("fun")
 
-  def foo[P](erased x: Int)(erased y: Int): Int = 0
+  inline def foo[P](erased x: Int)(erased y: Int): Int = 0
 
-  def bar(x: Int) =  {
-    println(x)
+  inline def bar(x: Int) =  {
     x
   }
 }
diff --git a/tests/run/i11996.scala b/tests/run/i11996.scala
index 9724e12b575e..a4318ace6c86 100644
--- a/tests/run/i11996.scala
+++ b/tests/run/i11996.scala
@@ -3,8 +3,8 @@
 final class UnivEq[A]
 
 object UnivEq:
-  erased def force[A]: UnivEq[A] =
-    compiletime.erasedValue
+  inline def force[A]: UnivEq[A] =
+    caps.unsafe.unsafeErasedValue
 
 extension [A](a: A)
   inline def ==*[B >: A](b: B)(using erased UnivEq[B]): Boolean = a == b
diff --git a/tests/run/i16943.scala b/tests/run/i16943.scala
index 68e1f8fb5aa3..697e9a2f38b7 100644
--- a/tests/run/i16943.scala
+++ b/tests/run/i16943.scala
@@ -1,6 +1,6 @@
 @main
 @annotation.experimental
-def Test(): Unit = fail(compiletime.erasedValue, 1)
+def Test(): Unit = fail(caps.unsafe.unsafeErasedValue, 1)
 
 @annotation.experimental
 def fail(dumb: CanThrow[Exception], x: Int) = println(x)
diff --git a/tests/semanticdb/metac.expect b/tests/semanticdb/metac.expect
index 3f904b6bdda0..5f755e375ec3 100644
--- a/tests/semanticdb/metac.expect
+++ b/tests/semanticdb/metac.expect
@@ -2974,6 +2974,7 @@ Text => empty
 Language => Scala
 Symbols => 16 entries
 Occurrences => 12 entries
+Diagnostics => 2 entries
 
 Symbols:
 example/NamedArguments# => class NamedArguments extends Object { self: NamedArguments => +4 decls }
@@ -3007,6 +3008,10 @@ Occurrences:
 [5:7..5:12): apply -> example/NamedArguments#User.apply().
 [5:13..5:17): name -> example/NamedArguments#User.apply().(name)
 
+Diagnostics:
+[4:2..4:21): [warning] A pure expression does nothing in statement position
+[5:2..5:27): [warning] A pure expression does nothing in statement position
+
 expect/NewModifiers.scala
 -------------------------
 
@@ -3654,7 +3659,7 @@ Text => empty
 Language => Scala
 Symbols => 62 entries
 Occurrences => 165 entries
-Diagnostics => 3 entries
+Diagnostics => 4 entries
 Synthetics => 39 entries
 
 Symbols:
@@ -3890,6 +3895,7 @@ Occurrences:
 
 Diagnostics:
 [19:21..19:22): [warning] unused pattern variable
+[28:4..28:9): [warning] A pure expression does nothing in statement position
 [41:4..41:5): [warning] unused pattern variable
 [63:10..63:11): [warning] unused explicit parameter