Skip to content
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
5 changes: 5 additions & 0 deletions compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,11 @@ object Types extends TypeUtils {
/** If this is a proto type, WildcardType, otherwise the type itself */
def dropIfProto: Type = this

/** If this is a (possibly applied) selection proto type, ignore the
* selection part
*/
def ignoreSelectionProto(using Context): Type = this

/** If this is an AndType, the number of factors, 1 for all other types */
def andFactorCount: Int = 1

Expand Down
8 changes: 6 additions & 2 deletions compiler/src/dotty/tools/dotc/printing/RefinedPrinter.scala
Original file line number Diff line number Diff line change
Expand Up @@ -354,8 +354,12 @@ class RefinedPrinter(_ctx: Context) extends PlainPrinter(_ctx) {
~ "]"
case IgnoredProto(ignored) =>
"?" ~ ("(ignored: " ~ toText(ignored) ~ ")").provided(printDebug)
case tp @ PolyProto(targs, resType) =>
"[applied to [" ~ toTextGlobal(targs, ", ") ~ "] returning " ~ toText(resType)
case tp @ PolyProto(targs, resultType) =>
"[applied to ["
~ toTextGlobal(targs, ", ")
~ "] returning "
~ toText(resultType)
~ "]"
case _ =>
super.toText(tp)
}
Expand Down
3 changes: 1 addition & 2 deletions compiler/src/dotty/tools/dotc/typer/Applications.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1422,7 +1422,7 @@ trait Applications extends Compatibility {
val typedArgs = if (isNamed) typedNamedArgs(tree.args) else tree.args.mapconserve(typedType(_))
record("typedTypeApply")

typedExpr(tree.fun, PolyProto(typedArgs, pt)) match {
typedExpr(tree.fun, PolyProto(typedArgs, pt.ignoreSelectionProto)) match
case fun: TypeApply if !ctx.isAfterTyper =>
val function = fun.fun
val args = (fun.args ++ tree.args).map(_.show).mkString(", ")
Expand All @@ -1446,7 +1446,6 @@ trait Applications extends Compatibility {
}
if (typedFn.tpe eq TryDynamicCallType) tryDynamicTypeApply()
else assignType(cpy.TypeApply(tree)(typedFn, typedArgs), typedFn, typedArgs)
}
}

/** Rewrite `new Array[T](....)` if T is an unbounded generic to calls to newGenericArray.
Expand Down
34 changes: 30 additions & 4 deletions compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,15 @@ object ProtoTypes {
override def viewExists(tp: Type, pt: Type)(using Context): Boolean = false
}

/** A trait for prototypes that match all types */
trait MatchAlways extends ProtoType {
def isMatchedBy(tp1: Type, keepConstraint: Boolean)(using Context): Boolean = true
/** A trait for prototypes that map to themselves */
trait FixedProto extends ProtoType:
def map(tm: TypeMap)(using Context): ProtoType = this
def fold[T](x: T, ta: TypeAccumulator[T])(using Context): T = x
override def toString: String = getClass.toString
}

/** A trait for prototypes that match all types */
trait MatchAlways extends FixedProto:
def isMatchedBy(tp1: Type, keepConstraint: Boolean)(using Context): Boolean = true

/** A class marking ignored prototypes that can be revealed by `deepenProto` */
abstract case class IgnoredProto(ignored: Type) extends CachedGroundType with MatchAlways:
Expand All @@ -179,6 +181,21 @@ object ProtoTypes {
ignored
override def deepenProtoTrans(using Context): Type = ignored.deepenProtoTrans

override def isMatchedBy(tp1: Type, keepConstraint: Boolean)(using Context): Boolean =
def takesParams(tp: Type): Boolean = tp match
case tp: PolyType => takesParams(tp.resType)
case MethodType(pnames) => pnames.nonEmpty && !tp.isImplicitMethod
case _ => false
ignored match
case ignored: SelectionProto if ignored.name != nme.apply =>
// Non-implicit methods that take at least one parameter don't match ignored
// selection protos unless the selection is via `apply`. This is because a
// match of a different selection would require an eta expansion _and_ an
// implicit conversion, which is not allowed. So the prototype would not
// match even if implicit conversions were present. Test case: i23773a.scala.
!takesParams(tp1.widen)
case _ => true

/** Did someone look inside via deepenProto? Used for error deagniostics
* to give a more extensive expected type.
*/
Expand Down Expand Up @@ -286,6 +303,9 @@ object ProtoTypes {
override def deepenProtoTrans(using Context): SelectionProto =
derivedSelectionProto(name, memberProto.deepenProtoTrans, compat, nameSpan)

override def ignoreSelectionProto(using Context): IgnoredProto =
IgnoredProto(this)

override def computeHash(bs: Hashable.Binders): Int = {
val delta = (if (compat eq NoViewsAllowed) 1 else 0) | (if (privateOK) 2 else 0)
addDelta(doHash(bs, name, memberProto), delta)
Expand Down Expand Up @@ -620,6 +640,9 @@ object ProtoTypes {
override def deepenProtoTrans(using Context): FunProto =
derivedFunProto(args, resultType.deepenProtoTrans, constrainResultDeep = true)

override def ignoreSelectionProto(using Context): FunProto =
derivedFunProto(args, resultType.ignoreSelectionProto)

override def withContext(newCtx: Context): ProtoType =
if newCtx `eq` protoCtx then this
else new FunProto(args, resType)(typer, applyKind, state)(using newCtx)
Expand Down Expand Up @@ -734,6 +757,9 @@ object ProtoTypes {

override def deepenProtoTrans(using Context): PolyProto =
derivedPolyProto(targs, resultType.deepenProtoTrans)

override def ignoreSelectionProto(using Context): PolyProto =
derivedPolyProto(targs, resultType.ignoreSelectionProto)
}

/** A prototype for expressions [] that are known to be functions:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ object Test extends App {
def foo[T]: Show[T] = new Show[T](2)
}

assert(a.foo[Int].i == 1) // error: no implicit argument of type Test.Context was found for parameter ctx
assert(a.foo[Int].i == 1) // error: no implicit argument of type Test.Context was found for parameter ctx, was OK
}
10 changes: 10 additions & 0 deletions tests/pos/i23773.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
trait Foo[T]

def foo[A]: Int = ???
def foo[A: Foo]: Int = ???

extension (x: Int)
def succ: Int = x + 1

val a = foo[Int]
val b = foo[Int].succ // error
19 changes: 19 additions & 0 deletions tests/pos/i23773a.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
trait NumericDate
trait JWSDecoded[H]

trait StandardHeaderWrite[H]:
def setAlgorithm(header: H, algorithm: Algorithm): H

object StandardHeaderWrite:
def apply[H](using sh: StandardHeaderWrite[H]): StandardHeaderWrite[H] = ???
// unused - required to reproduce
def apply[H](setAlg: (H, Algorithm) => H): StandardHeaderWrite[H] = ???

final case class JWK(algorithm: Option[Algorithm])
sealed trait Algorithm

def Test[F[_], H](key: JWK, header: H)(using StandardHeaderWrite[H]) = {
key.algorithm
.map(StandardHeaderWrite[H].setAlgorithm(header, _))
.getOrElse(header)
}
Loading