Skip to content

Commit

Permalink
Fix #18649: Use loBound of param types when materializing a context f…
Browse files Browse the repository at this point in the history
…unction. (#18651)

Since the param types come from type arguments to
`ContextFunctionN[...]`, nothing prevents them a priori from being
wildcard type params, i.e., `TypeBounds`. However, that is not a valid
type to give to a concrete term param.

We can arbitrarily choose any type that conforms to the bounds, which
realistically means one of the two bounds. Since type inference already
chooses the lower bound when explicitly writing the context function, we
align and choose the lower bound when materializing it.
  • Loading branch information
sjrd authored Oct 12, 2023
2 parents 98215d3 + 242e68f commit 85d55e7
Show file tree
Hide file tree
Showing 3 changed files with 16 additions and 1 deletion.
8 changes: 8 additions & 0 deletions compiler/src/dotty/tools/dotc/transform/TreeChecker.scala
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,14 @@ object TreeChecker {
super.typedClassDef(cdef, cls)
}

override def typedValDef(vdef: untpd.ValDef, sym: Symbol)(using Context): Tree =
val tpdTree = super.typedValDef(vdef, sym)
vdef.tpt.tpe match
case _: ValueType => () // ok
case _: ExprType if sym.isOneOf(TermParamOrAccessor) => () // ok
case _ => assert(false, i"wrong type, expected a value type for ${sym.fullName}, but found: ${sym.info}")
tpdTree

override def typedDefDef(ddef: untpd.DefDef, sym: Symbol)(using Context): Tree =
def defParamss = ddef.paramss.filter(!_.isEmpty).nestedMap(_.symbol)
def layout(symss: List[List[Symbol]]): String =
Expand Down
2 changes: 1 addition & 1 deletion compiler/src/dotty/tools/dotc/typer/Typer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3242,7 +3242,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
val paramTypes = {
val hasWildcard = formals.exists(_.existsPart(_.isInstanceOf[WildcardType], StopAt.Static))
if hasWildcard then formals.map(_ => untpd.TypeTree())
else formals.map(untpd.TypeTree)
else formals.map(formal => untpd.TypeTree(formal.loBound)) // about loBound, see tests/pos/i18649.scala
}

val erasedParams = pt match {
Expand Down
7 changes: 7 additions & 0 deletions tests/pos/i18649.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
object Test:
// always inferred Nothing for `x`
def contextFunctionWildcardExplicit: ? ?=> String = x ?=> "foo"

// used to infer TYPEBOUNDS for the type of the argument
def contextFunctionWildcardInserted: ? ?=> String = "foo"
end Test

0 comments on commit 85d55e7

Please sign in to comment.