Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions compiler/src/dotty/tools/dotc/core/Definitions.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1078,6 +1078,7 @@ class Definitions {
@tu lazy val ThrowsAnnot: ClassSymbol = requiredClass("scala.throws")
@tu lazy val TransientAnnot: ClassSymbol = requiredClass("scala.transient")
@tu lazy val UncheckedAnnot: ClassSymbol = requiredClass("scala.unchecked")
@tu lazy val UncheckedOverrideAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedOverride")
@tu lazy val UncheckedStableAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedStable")
@tu lazy val UncheckedVarianceAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedVariance")
@tu lazy val UncheckedCapturesAnnot: ClassSymbol = requiredClass("scala.annotation.unchecked.uncheckedCaptures")
Expand Down
8 changes: 5 additions & 3 deletions compiler/src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,8 @@ object RefChecks {
if makeOverridingPairsChecker == null then OverridingPairsChecker(clazz, self)
else makeOverridingPairsChecker(clazz, self)

def isMarkedOverride(sym: Symbol) = sym.isAnyOverride || sym.hasAnnotation(defn.UncheckedOverrideAnnot)

/* Check that all conditions for overriding `other` by `member`
* of class `clazz` are met.
*/
Expand Down Expand Up @@ -539,7 +541,7 @@ object RefChecks {
)
&& !member.is(Deferred)
&& !other.name.is(DefaultGetterName)
&& !member.isAnyOverride
&& !isMarkedOverride(member)
then
// Exclusion for default getters, fixes SI-5178. We cannot assign the Override flag to
// the default getter: one default getter might sometimes override, sometimes not. Example in comment on ticket.
Expand Down Expand Up @@ -569,9 +571,9 @@ object RefChecks {
overrideError("needs `override` modifier")
else if (other.is(AbsOverride) && other.isIncompleteIn(clazz) && !member.is(AbsOverride))
overrideError("needs `abstract override` modifiers")
else if member.is(Override) && other.isMutableVarOrAccessor then
else if isMarkedOverride(member) && other.isMutableVarOrAccessor then
overrideError("cannot override a mutable variable")
else if member.isAnyOverride
else if isMarkedOverride(member)
&& !(member.owner.thisType.baseClasses.exists(_.isSubClass(other.owner)))
&& !member.is(Deferred) && !other.is(Deferred)
&& intersectionIsEmpty(member.extendedOverriddenSymbols, other.extendedOverriddenSymbols)
Expand Down
22 changes: 22 additions & 0 deletions library/src/scala/annotation/unchecked/uncheckedOverride.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Scala (https://www.scala-lang.org)
*
* Copyright EPFL and Lightbend, Inc. dba Akka
*
* Licensed under Apache License 2.0
* (http://www.apache.org/licenses/LICENSE-2.0).
*
* See the NOTICE file distributed with this work for
* additional information regarding copyright ownership.
*/

package scala.annotation.unchecked

import scala.annotation.StaticAnnotation
import scala.language.`2.13`

/**
* Marking a definition `@uncheckedOverride` is equivalent to the `override` keyword, except that overriding is not
* enforced. A definition marked `@uncheckedOverride` is allowed to override nothing.
*/
final class uncheckedOverride extends StaticAnnotation
6 changes: 3 additions & 3 deletions library/src/scala/math/Ordering.scala
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ package math

import scala.language.`2.13`
import java.util.Comparator

import scala.language.implicitConversions
import scala.annotation.migration
import scala.annotation.unchecked.uncheckedOverride

/** Ordering is a trait whose instances each represent a strategy for sorting
* instances of a type.
Expand Down Expand Up @@ -104,10 +104,10 @@ trait Ordering[T] extends Comparator[T] with PartialOrdering[T] with Serializabl
override def equiv(x: T, y: T): Boolean = compare(x, y) == 0

/** Return `x` if `x` >= `y`, otherwise `y`. */
def max[U <: T](x: U, y: U): U = if (gteq(x, y)) x else y
@uncheckedOverride def max[U <: T](x: U, y: U): U = if (gteq(x, y)) x else y

/** Return `x` if `x` <= `y`, otherwise `y`. */
def min[U <: T](x: U, y: U): U = if (lteq(x, y)) x else y
@uncheckedOverride def min[U <: T](x: U, y: U): U = if (lteq(x, y)) x else y

/** Return the opposite ordering of this one.
*
Expand Down
5 changes: 4 additions & 1 deletion project/MiMaFilters.scala
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ object MiMaFilters {
ProblemFilters.exclude[DirectMissingMethodProblem]("scala.NamedTuple.namedTupleOrdering"),
ProblemFilters.exclude[MissingClassProblem]("scala.NamedTuple$namedTupleOrdering"),

// cc related
// scala/scala3#24545
ProblemFilters.exclude[MissingClassProblem]("scala.annotation.unchecked.uncheckedOverride"),

// cc related
ProblemFilters.exclude[MissingClassProblem]("scala.annotation.internal.readOnlyCapability"),
ProblemFilters.exclude[MissingClassProblem]("scala.annotation.internal.onlyCapability"),
ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language#experimental.separationChecking"),
Expand Down
27 changes: 27 additions & 0 deletions tests/pos/t13127.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import scala.annotation.unchecked.uncheckedOverride

trait Hordering[T] extends java.util.Comparator[T] {
// overriding on java 26 and later, not overriding before
@uncheckedOverride def max[U <: T](x: U, y: U): U = x
@uncheckedOverride def min[U <: T](x: U, y: U): U = x
}

trait Base[T] {
def max[U <: T](x: U, y: U): U = x

def mux(x: String = "ex") = x
}

trait Sub[T] extends Base[T] {
@uncheckedOverride def max[U <: T](x: U, y: U): U = x // overriding ok
@uncheckedOverride def min[U <: T](x: U, y: U): U = x // not overriding ok

// overriding default
@uncheckedOverride def mux(x: String = "nox") = x

def test = mux()
}

trait OverrideOrdering[T] extends scala.math.Ordering[T] {
override def max[U <: T](x: U, y: U): U = x
}
Loading