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
4 changes: 2 additions & 2 deletions compiler/src/dotty/tools/dotc/core/Contexts.scala
Original file line number Diff line number Diff line change
Expand Up @@ -810,11 +810,11 @@ object Contexts {
final def addMode(mode: Mode): c.type = c.setMode(c.mode | mode)
final def retractMode(mode: Mode): c.type = c.setMode(c.mode &~ mode)

/** Run `op` with a pool-allocated context that has an ExporeTyperState. */
/** Run `op` with a pool-allocated context that has an ExploreTyperState. */
inline def explore[T](inline op: Context ?=> T)(using Context): T =
exploreInFreshCtx(op)

/** Run `op` with a pool-allocated FreshContext that has an ExporeTyperState. */
/** Run `op` with a pool-allocated FreshContext that has an ExploreTyperState. */
inline def exploreInFreshCtx[T](inline op: FreshContext ?=> T)(using Context): T =
val pool = ctx.base.exploreContextPool
val nestedCtx = pool.next()
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/core/Types.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2312,7 +2312,7 @@ object Types extends TypeUtils {

/** A trait for proto-types, used as expected types in typer */
trait ProtoType extends Type {
def isMatchedBy(tp: Type, keepConstraint: Boolean = false)(using Context): Boolean
def isMatchedBy(tp: Type, keepConstraint: Boolean)(using Context): Boolean
def fold[T](x: T, ta: TypeAccumulator[T])(using Context): T
def map(tm: TypeMap)(using Context): ProtoType

Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Implicits.scala
Original file line number Diff line number Diff line change
Expand Up @@ -1207,7 +1207,7 @@ trait Implicits:

def tryConversionForSelection(using Context) =
val converted = tryConversion
if !ctx.reporter.hasErrors && !selProto.isMatchedBy(converted.tpe) then
if !ctx.reporter.hasErrors && !selProto.isMatchedBy(converted.tpe, keepConstraint = false) then
// this check is needed since adapting relative to a `SelectionProto` can succeed
// even if the term is not a subtype of the `SelectionProto`
err.typeMismatch(converted, selProto)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ trait ImportSuggestions:
// To regain precision, test both sides separately.
test(ViewProto(argType, rt1)) || test(ViewProto(argType, rt2))
case pt: ViewProto =>
pt.isMatchedBy(ref)
pt.isMatchedBy(ref, keepConstraint = false)
case _ =>
normalize(ref, pt) <:< pt
test(pt)
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/ProtoTypes.scala
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ object ProtoTypes {

constFoldException(pt) || {
if Inlines.isInlineable(meth) then
// Stricter behavisour in 3.4+: do not apply `wildApprox` to non-transparent inlines
// Stricter behaviour in 3.4+: do not apply `wildApprox` to non-transparent inlines
// unless their return type is a MatchType. In this case there's no reason
// not to constrain type variables in the expected type. For transparent inlines
// we do not want to constrain type variables in the expected type since the
Expand Down
28 changes: 14 additions & 14 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4174,7 +4174,8 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
Some(adapt(tree, pt, locked))
else
val selProto = SelectionProto(name, pt, NoViewsAllowed, privateOK = false, tree.nameSpan)
if selProto.isMatchedBy(qual.tpe) || tree.hasAttachment(InsertedImplicitOnQualifier) then
if selProto.isMatchedBy(qual.tpe, keepConstraint = false) || tree.hasAttachment(InsertedImplicitOnQualifier)
then
None
else
tryEither {
Expand Down Expand Up @@ -4472,12 +4473,15 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
def argHasDefault = hasDefaultParams && !defaultArg.isEmpty

def canProfitFromMoreConstraints =
!ctx.mode.is(Mode.ImplicitExploration)
&& {
arg.tpe.isInstanceOf[AmbiguousImplicits]
// Ambiguity could be decided by more constraints
|| !isFullyDefined(formal, ForceDegree.none) && !argHasDefault
// More context might constrain type variables which could make implicit scope larger.
// But in this case we should search with additional arguments typed only if there
// is no default argument.
}

// Try to constrain the result using `pt1`, but back out if a BadTyperStateAssertion
// is thrown. TODO Find out why the bad typer state arises and prevent it. The try-catch
Expand All @@ -4491,7 +4495,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
arg.tpe match
case failed: SearchFailureType if canProfitFromMoreConstraints =>
val pt1 = pt.deepenProtoTrans
if (pt1 `ne` pt) && (pt1 ne sharpenedPt) && tryConstrainResult(pt1) then
if (pt1 ne pt) && (pt1 ne sharpenedPt) && tryConstrainResult(pt1) then
return implicitArgs(formals, argIndex, pt1)
case _ =>

Expand Down Expand Up @@ -4584,11 +4588,9 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
issueErrors(tree, args, failureType)
else
val app = cpy.Apply(tree)(untpd.TypedSplice(tree), namedArgs)
// old-style implicit needs to be marked using so that implicits are searched
val needsUsing = wtp.isImplicitMethod || wtp.match
case MethodType(ContextBoundParamName(_) :: _) => sourceVersion.isAtLeast(`3.4`)
case _ => false
if needsUsing then app.setApplyKind(ApplyKind.Using)
// avoid warning if method is old-style implicit that context bounds will be contextual
// also required for correctly reporting implicit not found
app.setApplyKind(ApplyKind.Using)
typr.println(i"try with default implicit args $app")
// If the retyped tree still has an error type and is an `Apply`
// node, we can report the errors for each argument nicely.
Expand All @@ -4605,13 +4607,11 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
// Reset context in case it was set to a supercall context before.
// otherwise the invariant for taking another this or super call context is not met.
// Test case is i20483.scala
tree match
case tree: Block =>
readaptSimplified(tpd.Block(tree.stats, tpd.Apply(tree.expr, args)))
case tree: NamedArg =>
readaptSimplified(tpd.NamedArg(tree.name, tpd.Apply(tree.arg, args)))
case _ =>
readaptSimplified(tpd.Apply(tree, args))
val cpy = tree match
case tree: Block => tpd.Block(tree.stats, tpd.Apply(tree.expr, args))
case tree: NamedArg => tpd.NamedArg(tree.name, tpd.Apply(tree.arg, args))
case _ => tpd.Apply(tree, args)
readaptSimplified(cpy)
end addImplicitArgs

pt.revealIgnored match {
Expand Down
4 changes: 4 additions & 0 deletions tests/neg/i19594.check
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,7 @@
26 | h(true, 1) // error
| ^^^^^^^^^^
| No given instance of type String was found
-- [E172] Type Error: tests/neg/i19594.scala:31:11 ---------------------------------------------------------------------
31 | competing(true, 42) // error when the default is in the same param list as the missing implicit
| ^^^^^^^^^^^^^^^^^^^
| Can you see me?!
5 changes: 5 additions & 0 deletions tests/neg/i19594.scala
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,8 @@ object updated:

def h[A, B](a: A, b: B)(using c: Compare[A, B] = Compare.any, s: String) = ()
h(true, 1) // error

class X
val defx = X()
def competing[A, B](a: A, b: B)(implicit x: X = defx, cmp: Compare[A, B]) = ()
competing(true, 42) // error when the default is in the same param list as the missing implicit
27 changes: 27 additions & 0 deletions tests/pos/i24192.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import scala.language.implicitConversions

// https://github.com/scala/scala-collection-contrib/blob/main/src/main/scala/scala/collection/decorators/package.scala
object decorators {
trait IsMap[A]
implicit def mapDecorator[C](coll: C)(implicit map: IsMap[C]): Map[C, map.type] = ???
}
import decorators.mapDecorator // unused, required to reproduce

trait Eq[T]
trait Applicative[F[_]]
given Applicative[Option] = ???

trait Traverse[F[_]]:
// context bound required to reproduce
def sequence[G[_]: Applicative, A](fga: F[G[A]]): G[F[A]] = ???

object Traverse:
def apply[F[_]]: Traverse[F] = ???

trait Segment[Element: Eq]

case class MergeResult[Element: Eq] private (segments: Seq[Segment[Element]]):
def thisFailsToCompile(): Option[MergeResult[Element]] =
Traverse[Seq]
.sequence(Seq.empty[Option[Segment[Element]]])
.map(MergeResult.apply) // no error
13 changes: 13 additions & 0 deletions tests/warn/i19506.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
//> using options -source 3.4

trait Reader[T]
def read[T: Reader](s: String, trace: Boolean = false)(implicit i: Int = 42): T = ???

// if apply kind is not using when retrying to insert the default arg, it will warn:
// Context bounds will map to context parameters.
// A `using` clause is needed to pass explicit arguments to them.
// The method to invoke (read) might have been compiled under 3.3,
// or (as above) the contextual parameter may have been merged with an existing implicit param list.
def Test =
implicit def reader: Reader[Object] = new Reader[Object]{}
read[Object]("") // no warn
11 changes: 11 additions & 0 deletions tests/warn/i22439.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@main def test() =
given Int = 42

locally:
given String = "y"
def ff(implicit i: Int, s: String = "x") = s * i
def gg(using i: Int, s: String = "x") = s * i
ff(using i = 10) // warn uses default arg
gg(using i = 10) // warn
ff(i = 10) // warn should use using
gg(i = 10) // remarkably, augmentString(gg(given_Int, given_String)).apply(i = 10)
Loading