Skip to content

Commit 127f346

Browse files
authored
Merge pull request #7838 from dotty-staging/fix-#7810
Fix #7810: Survive wildcards when summoning a ValueOf
2 parents 47b62c1 + 4a3113f commit 127f346

22 files changed

+145
-185
lines changed

compiler/src/dotty/tools/dotc/ast/Desugar.scala

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -723,10 +723,7 @@ object desugar {
723723
else if (companionMembers.nonEmpty || companionDerived.nonEmpty || isEnum)
724724
companionDefs(anyRef, companionMembers)
725725
else if (isValueClass)
726-
impl.constr.vparamss match {
727-
case (_ :: Nil) :: _ => companionDefs(anyRef, Nil)
728-
case _ => Nil // error will be emitted in typer
729-
}
726+
companionDefs(anyRef, Nil)
730727
else Nil
731728

732729
enumCompanionRef match {

compiler/src/dotty/tools/dotc/core/TypeComparer.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1494,6 +1494,7 @@ class TypeComparer(initctx: Context) extends ConstraintHandling[AbsentContext] w
14941494
case tp: SingletonType if tp.isStable => tp
14951495
case tp: ValueType => SkolemType(tp)
14961496
case tp: TypeProxy => ensureStableSingleton(tp.underlying)
1497+
case tp => assert(ctx.reporter.errorsReported); SkolemType(tp)
14971498
}
14981499

14991500
/** Skip refinements in `tp2` which match corresponding refinements in `tp1`.

compiler/src/dotty/tools/dotc/core/Types.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4603,7 +4603,7 @@ object Types {
46034603

46044604
case tp: AppliedType =>
46054605
def mapArgs(args: List[Type], tparams: List[ParamInfo]): List[Type] = args match {
4606-
case arg :: otherArgs =>
4606+
case arg :: otherArgs if tparams.nonEmpty =>
46074607
val arg1 = arg match {
46084608
case arg: TypeBounds => this(arg)
46094609
case arg => atVariance(variance * tparams.head.paramVariance)(this(arg))

compiler/src/dotty/tools/dotc/transform/Erasure.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ object Erasure {
348348
tree.symbol.getAnnotation(defn.CompileTimeOnlyAnnot) match {
349349
case Some(annot) =>
350350
def defaultMsg =
351-
s"""Reference to ${tree.symbol.showLocated} should not have survived,
351+
i"""Reference to ${tree.symbol.showLocated} should not have survived,
352352
|it should have been processed and eliminated during expansion of an enclosing macro or term erasure."""
353353
val message = annot.argumentConstant(0).fold(defaultMsg)(_.stringValue)
354354
ctx.error(message, tree.sourcePos)
@@ -750,8 +750,11 @@ object Erasure {
750750

751751
override def adapt(tree: Tree, pt: Type, locked: TypeVars)(implicit ctx: Context): Tree =
752752
trace(i"adapting ${tree.showSummary}: ${tree.tpe} to $pt", show = true) {
753-
assert(ctx.phase == ctx.erasurePhase || ctx.phase == ctx.erasurePhase.next, ctx.phase)
754-
if (tree.isEmpty) tree
753+
if ctx.phase != ctx.erasurePhase && ctx.phase != ctx.erasurePhase.next then
754+
// this can happen when reading annotations loaded during erasure,
755+
// since these are loaded at phase typer.
756+
adapt(tree, pt, locked)(given ctx.withPhase(ctx.erasurePhase.next))
757+
else if (tree.isEmpty) tree
755758
else if (ctx.mode is Mode.Pattern) tree // TODO: replace with assertion once pattern matcher is active
756759
else adaptToType(tree, pt)
757760
}

compiler/src/dotty/tools/dotc/typer/Applications.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -987,7 +987,10 @@ trait Applications extends Compatibility {
987987

988988
/** Overridden in ReTyper to handle primitive operations that can be generated after erasure */
989989
protected def handleUnexpectedFunType(tree: untpd.Apply, fun: Tree)(implicit ctx: Context): Tree =
990-
throw new Error(i"unexpected type.\n fun = $fun,\n methPart(fun) = ${methPart(fun)},\n methPart(fun).tpe = ${methPart(fun).tpe},\n tpe = ${fun.tpe}")
990+
if ctx.reporter.errorsReported then
991+
throw TypeError(i"unexpected function type: ${methPart(fun).tpe}")
992+
else
993+
throw Error(i"unexpected type.\n fun = $fun,\n methPart(fun) = ${methPart(fun)},\n methPart(fun).tpe = ${methPart(fun).tpe},\n tpe = ${fun.tpe}")
991994

992995
def typedNamedArgs(args: List[untpd.Tree])(implicit ctx: Context): List[NamedArg] =
993996
for (arg @ NamedArg(id, argtpt) <- args) yield {

compiler/src/dotty/tools/dotc/typer/Implicits.scala

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,7 @@ trait Implicits { self: Typer =>
859859
(formal, span) => implicit ctx => {
860860
def success(t: Tree) = New(defn.ValueOfClass.typeRef.appliedTo(t.tpe), t :: Nil).withSpan(span)
861861

862-
formal.argTypes match {
862+
formal.argInfos match {
863863
case arg :: Nil =>
864864
fullyDefinedType(arg.dealias, "ValueOf argument", span) match {
865865
case ConstantType(c: Constant) =>
@@ -1389,18 +1389,17 @@ trait Implicits { self: Typer =>
13891389
untpd.Apply(untpdConv, untpd.TypedSplice(argument) :: Nil),
13901390
pt, locked)
13911391
}
1392-
if (cand.isExtension) {
1393-
val SelectionProto(name: TermName, mbrType, _, _) = pt
1394-
val result = extMethodApply(untpd.Select(untpdGenerated, name), argument, mbrType)
1395-
if (!ctx.reporter.hasErrors && cand.isConversion) {
1396-
val testCtx = ctx.fresh.setExploreTyperState()
1397-
tryConversion(testCtx)
1398-
if (testCtx.reporter.hasErrors)
1399-
ctx.error(em"ambiguous implicit: $generated is eligible both as an implicit conversion and as an extension method container")
1400-
}
1401-
result
1402-
}
1403-
else tryConversion
1392+
pt match
1393+
case SelectionProto(name: TermName, mbrType, _, _) if cand.isExtension =>
1394+
val result = extMethodApply(untpd.Select(untpdGenerated, name), argument, mbrType)
1395+
if !ctx.reporter.hasErrors && cand.isConversion then
1396+
val testCtx = ctx.fresh.setExploreTyperState()
1397+
tryConversion(testCtx)
1398+
if testCtx.reporter.hasErrors then
1399+
ctx.error(em"ambiguous implicit: $generated is eligible both as an implicit conversion and as an extension method container")
1400+
result
1401+
case _ =>
1402+
tryConversion
14041403
}
14051404
if (ctx.reporter.hasErrors) {
14061405
ctx.reporter.removeBufferedMessages

compiler/src/dotty/tools/dotc/typer/Typer.scala

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,10 @@ class Typer extends Namer
12331233
def caseRest(implicit ctx: Context) = {
12341234
val pat1 = checkSimpleKinded(typedType(cdef.pat)(ctx.addMode(Mode.Pattern)))
12351235
val pat2 = indexPattern(cdef).transform(pat1)
1236-
val body1 = typedType(cdef.body, pt)
1236+
var body1 = typedType(cdef.body, pt)
1237+
if !body1.isType then
1238+
assert(ctx.reporter.errorsReported)
1239+
body1 = TypeTree(errorType("<error: not a type>", cdef.sourcePos))
12371240
assignType(cpy.CaseDef(cdef)(pat2, EmptyTree, body1), pat2, body1)
12381241
}
12391242
caseRest(ctx.fresh.setFreshGADTBounds.setNewScope)
@@ -1548,7 +1551,13 @@ class Typer extends Namer
15481551

15491552
def typedAlternative(tree: untpd.Alternative, pt: Type)(implicit ctx: Context): Alternative = {
15501553
val nestedCtx = ctx.addMode(Mode.InPatternAlternative)
1554+
def ensureValueTypeOrWildcard(tree: Tree) =
1555+
if tree.tpe.isValueTypeOrWildcard then tree
1556+
else
1557+
assert(ctx.reporter.errorsReported)
1558+
tree.withType(defn.AnyType)
15511559
val trees1 = tree.trees.mapconserve(typed(_, pt)(nestedCtx))
1560+
.mapconserve(ensureValueTypeOrWildcard)
15521561
assignType(cpy.Alternative(tree)(trees1), trees1)
15531562
}
15541563

@@ -1924,13 +1933,17 @@ class Typer extends Namer
19241933
val annot1 = typedExpr(tree.annot, defn.AnnotationClass.typeRef)
19251934
val arg1 = typed(tree.arg, pt)
19261935
if (ctx.mode is Mode.Type) {
1927-
val result = assignType(cpy.Annotated(tree)(arg1, annot1), arg1, annot1)
1928-
result.tpe match {
1929-
case AnnotatedType(rhs, Annotation.WithBounds(bounds)) =>
1930-
if (!bounds.contains(rhs)) ctx.error(em"type $rhs outside bounds $bounds", tree.sourcePos)
1931-
case _ =>
1932-
}
1933-
result
1936+
if arg1.isType then
1937+
val result = assignType(cpy.Annotated(tree)(arg1, annot1), arg1, annot1)
1938+
result.tpe match {
1939+
case AnnotatedType(rhs, Annotation.WithBounds(bounds)) =>
1940+
if (!bounds.contains(rhs)) ctx.error(em"type $rhs outside bounds $bounds", tree.sourcePos)
1941+
case _ =>
1942+
}
1943+
result
1944+
else
1945+
assert(ctx.reporter.errorsReported)
1946+
TypeTree(UnspecifiedErrorType)
19341947
}
19351948
else {
19361949
val arg2 = arg1 match {

docs/docs/reference/contextual/extension-methods-new.md

Lines changed: 0 additions & 155 deletions
This file was deleted.

tests/neg/i7810.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
val a = implicitly[ValueOf[_]] // error

tests/neg/i7811.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trait A {
2+
type Type[X,] // error
3+
def a[X]: Type[X,] // error
4+
}
5+
class B extends A {
6+
type Type[X]
7+
var a = 1
8+
}

tests/neg/i7812.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def f(): Any = ???
2+
var f: (UndefinedA & UndefinedB) { val x: Int } = ??? // error // error
3+
val a = f // error

tests/neg/i7813.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
implicit def f[X <: Undefined](implicit a: Int): X = ??? // error
2+
def g(arg: h.NonExistent): Int = ???
3+
val h: Int = ???

tests/neg/i7814.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
def i0 = Unit // error

tests/neg/i7815.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait A {
2+
val a: Int match { case Int => this } // error
3+
}

tests/neg/i7816.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
object A {
2+
def f()(>) = ??? // error
3+
import f.NonExistent // error
4+
}

tests/neg/i7817.scala

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
trait Foo[A]
2+
class A {
3+
def F[x : Foo]() = ???
4+
5+
Int match {
6+
case Int | F => () // error
7+
}
8+
}

tests/neg/i7818.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
def foo = (x: @) => () // error

tests/pending/neg/i7820.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
object A { type F[X >: F, Y] }

tests/pending/pos/i7745.scala

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
trait F[x]
2+
implicit def foo[f[_], y, x <: f[y]](implicit ev: F[y]): F[x] = ???
3+
val test = implicitly

tests/pending/pos/i7778.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
object Example extends App {
2+
3+
final case class Foo[A](run: (given A) => Int)
4+
5+
}

0 commit comments

Comments
 (0)