Skip to content

Some small improvements #13606

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 30, 2021
Merged
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
6 changes: 5 additions & 1 deletion compiler/src/dotty/tools/dotc/ast/untpd.scala
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,11 @@ object untpd extends Trees.Instance[Untyped] with UntypedTreeInfo {
def AppliedTypeTree(tpt: Tree, arg: Tree)(implicit src: SourceFile): AppliedTypeTree =
AppliedTypeTree(tpt, arg :: Nil)

def TypeTree(tpe: Type)(using Context): TypedSplice = TypedSplice(TypeTree().withTypeUnchecked(tpe))
def TypeTree(tpe: Type)(using Context): TypedSplice =
TypedSplice(TypeTree().withTypeUnchecked(tpe))

def InferredTypeTree(tpe: Type)(using Context): TypedSplice =
TypedSplice(new InferredTypeTree().withTypeUnchecked(tpe))

def unitLiteral(implicit src: SourceFile): Literal = Literal(Constant(()))

Expand Down
6 changes: 5 additions & 1 deletion compiler/src/dotty/tools/dotc/transform/PostTyper.scala
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,11 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase
tree.fun,
tree.args.mapConserve(arg =>
if (methType.isImplicitMethod && arg.span.isSynthetic)
PruneErasedDefs.trivialErasedTree(arg)
arg match
case _: RefTree | _: Apply | _: TypeApply if arg.symbol.is(Erased) =>
dropInlines.transform(arg)
case _ =>
PruneErasedDefs.trivialErasedTree(arg)
else dropInlines.transform(arg)))
else
tree
Expand Down
93 changes: 49 additions & 44 deletions compiler/src/dotty/tools/dotc/typer/RefChecks.scala
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,54 @@ object RefChecks {

// Override checking ------------------------------------------------------------

/** A class for checking all overriding pairs of `class` with a given check function */
class OverridingPairsChecker(clazz: ClassSymbol, self: Type)(using Context) extends OverridingPairs.Cursor(clazz):

override def matches(sym1: Symbol, sym2: Symbol): Boolean =
isOverridingPair(sym1, sym2, self)

private def inLinearizationOrder(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
val owner1 = sym1.owner
val owner2 = sym2.owner
def precedesIn(bcs: List[ClassSymbol]): Boolean = (bcs: @unchecked) match
case bc :: bcs1 =>
if owner1 eq bc then true
else if owner2 eq bc then false
else precedesIn(bcs1)
case _ =>
false
precedesIn(parent.asClass.baseClasses)

// We can exclude pairs safely from checking only under two additional conditions
// - their signatures also match in the parent class.
// See neg/i12828.scala for an example where this matters.
// - They overriding/overridden appear in linearization order.
// See neg/i5094.scala for an example where this matters.
override def canBeHandledByParent(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
isOverridingPair(sym1, sym2, parent.thisType)
.showing(i"already handled ${sym1.showLocated}: ${sym1.asSeenFrom(parent.thisType).signature}, ${sym2.showLocated}: ${sym2.asSeenFrom(parent.thisType).signature} = $result", refcheck)
&& inLinearizationOrder(sym1, sym2, parent)

def checkAll(checkOverride: (Symbol, Symbol) => Unit) =
while hasNext do
checkOverride(overriding, overridden)
next()

// The OverridingPairs cursor does assume that concrete overrides abstract
// We have to check separately for an abstract definition in a subclass that
// overrides a concrete definition in a superclass. E.g. the following (inspired
// from neg/i11130.scala) needs to be rejected as well:
//
// class A { type T = B }
// class B extends A { override type T }
for dcl <- clazz.info.decls.iterator do
if dcl.is(Deferred) then
for other <- dcl.allOverriddenSymbols do
if !other.is(Deferred) then
checkOverride(dcl, other)
end checkAll
end OverridingPairsChecker

/** 1. Check all members of class `clazz` for overriding conditions.
* That is for overriding member M and overridden member O:
*
Expand Down Expand Up @@ -469,50 +517,7 @@ object RefChecks {
}*/
}

val opc = new OverridingPairs.Cursor(clazz):
override def matches(sym1: Symbol, sym2: Symbol): Boolean =
isOverridingPair(sym1, sym2, self)

private def inLinearizationOrder(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
val owner1 = sym1.owner
val owner2 = sym2.owner
def precedesIn(bcs: List[ClassSymbol]): Boolean = (bcs: @unchecked) match
case bc :: bcs1 =>
if owner1 eq bc then true
else if owner2 eq bc then false
else precedesIn(bcs1)
case _ =>
false
precedesIn(parent.asClass.baseClasses)

// We can exclude pairs safely from checking only under two additional conditions
// - their signatures also match in the parent class.
// See neg/i12828.scala for an example where this matters.
// - They overriding/overridden appear in linearization order.
// See neg/i5094.scala for an example where this matters.
override def canBeHandledByParent(sym1: Symbol, sym2: Symbol, parent: Symbol): Boolean =
isOverridingPair(sym1, sym2, parent.thisType)
.showing(i"already handled ${sym1.showLocated}: ${sym1.asSeenFrom(parent.thisType).signature}, ${sym2.showLocated}: ${sym2.asSeenFrom(parent.thisType).signature} = $result", refcheck)
&& inLinearizationOrder(sym1, sym2, parent)
end opc

while opc.hasNext do
checkOverride(opc.overriding, opc.overridden)
opc.next()

// The OverridingPairs cursor does assume that concrete overrides abstract
// We have to check separately for an abstract definition in a subclass that
// overrides a concrete definition in a superclass. E.g. the following (inspired
// from neg/i11130.scala) needs to be rejected as well:
//
// class A { type T = B }
// class B extends A { override type T }
for dcl <- clazz.info.decls.iterator do
if dcl.is(Deferred) then
for other <- dcl.allOverriddenSymbols do
if !other.is(Deferred) then
checkOverride(dcl, other)

OverridingPairsChecker(clazz, self).checkAll(checkOverride)
printMixinOverrideErrors()

// Verifying a concrete class has nothing unimplemented.
Expand Down
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1134,8 +1134,8 @@ class Typer extends Namer
*/
private def decomposeProtoFunction(pt: Type, defaultArity: Int, pos: SrcPos)(using Context): (List[Type], untpd.Tree) = {
def typeTree(tp: Type) = tp match {
case _: WildcardType => untpd.TypeTree()
case _ => untpd.TypeTree(tp)
case _: WildcardType => new untpd.InferredTypeTree()
case _ => untpd.InferredTypeTree(tp)
}
def interpolateWildcards = new TypeMap {
def apply(t: Type): Type = t match
Expand Down
10 changes: 10 additions & 0 deletions compiler/src/dotty/tools/dotc/util/SimpleIdentitySet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ abstract class SimpleIdentitySet[+Elem <: AnyRef] {
def contains[E >: Elem <: AnyRef](x: E): Boolean
def foreach(f: Elem => Unit): Unit
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean
def map[B <: AnyRef](f: Elem => B): SimpleIdentitySet[B]
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A
def toList: List[Elem]

Expand Down Expand Up @@ -55,6 +56,7 @@ object SimpleIdentitySet {
def contains[E <: AnyRef](x: E): Boolean = false
def foreach(f: Nothing => Unit): Unit = ()
def exists[E <: AnyRef](p: E => Boolean): Boolean = false
def map[B <: AnyRef](f: Nothing => B): SimpleIdentitySet[B] = empty
def /: [A, E <: AnyRef](z: A)(f: (A, E) => A): A = z
def toList = Nil
}
Expand All @@ -69,6 +71,8 @@ object SimpleIdentitySet {
def foreach(f: Elem => Unit): Unit = f(x0.asInstanceOf[Elem])
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean =
p(x0.asInstanceOf[E])
def map[B <: AnyRef](f: Elem => B): SimpleIdentitySet[B] =
Set1(f(x0.asInstanceOf[Elem]))
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A =
f(z, x0.asInstanceOf[E])
def toList = x0.asInstanceOf[Elem] :: Nil
Expand All @@ -86,6 +90,8 @@ object SimpleIdentitySet {
def foreach(f: Elem => Unit): Unit = { f(x0.asInstanceOf[Elem]); f(x1.asInstanceOf[Elem]) }
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean =
p(x0.asInstanceOf[E]) || p(x1.asInstanceOf[E])
def map[B <: AnyRef](f: Elem => B): SimpleIdentitySet[B] =
Set2(f(x0.asInstanceOf[Elem]), f(x1.asInstanceOf[Elem]))
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A =
f(f(z, x0.asInstanceOf[E]), x1.asInstanceOf[E])
def toList = x0.asInstanceOf[Elem] :: x1.asInstanceOf[Elem] :: Nil
Expand Down Expand Up @@ -114,6 +120,8 @@ object SimpleIdentitySet {
}
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean =
p(x0.asInstanceOf[E]) || p(x1.asInstanceOf[E]) || p(x2.asInstanceOf[E])
def map[B <: AnyRef](f: Elem => B): SimpleIdentitySet[B] =
Set3(f(x0.asInstanceOf[Elem]), f(x1.asInstanceOf[Elem]), f(x2.asInstanceOf[Elem]))
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A =
f(f(f(z, x0.asInstanceOf[E]), x1.asInstanceOf[E]), x2.asInstanceOf[E])
def toList = x0.asInstanceOf[Elem] :: x1.asInstanceOf[Elem] :: x2.asInstanceOf[Elem] :: Nil
Expand Down Expand Up @@ -156,6 +164,8 @@ object SimpleIdentitySet {
}
def exists[E >: Elem <: AnyRef](p: E => Boolean): Boolean =
xs.asInstanceOf[Array[E]].exists(p)
def map[B <: AnyRef](f: Elem => B): SimpleIdentitySet[B] =
SetN(xs.map(x => f(x.asInstanceOf[Elem]).asInstanceOf[AnyRef]))
def /: [A, E >: Elem <: AnyRef](z: A)(f: (A, E) => A): A =
xs.asInstanceOf[Array[E]].foldLeft(z)(f)
def toList: List[Elem] = {
Expand Down