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 @@ -2307,7 +2307,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 @@ -1221,7 +1221,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
23 changes: 14 additions & 9 deletions compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4148,7 +4148,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 @@ -4446,12 +4447,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 @@ -4465,7 +4469,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 @@ -4559,9 +4563,12 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
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
*/
val needsUsing = true //wtp.isImplicitMethod is asserted at beginning of method
if needsUsing then 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`
Expand All @@ -4579,13 +4586,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
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
Loading