diff --git a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala index 007dce352af5..c59c47a5a92b 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inferencing.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inferencing.scala @@ -43,7 +43,6 @@ object Inferencing { if (isFullyDefined(tp, ForceDegree.all)) tp else throw new Error(i"internal error: type of $what $tp is not fully defined, pos = $span") // !!! DEBUG - /** Instantiate selected type variables `tvars` in type `tp` */ def instantiateSelected(tp: Type, tvars: List[Type])(implicit ctx: Context): Unit = if (tvars.nonEmpty) diff --git a/compiler/src/dotty/tools/dotc/typer/Inliner.scala b/compiler/src/dotty/tools/dotc/typer/Inliner.scala index 70f6718de2da..a7087b51dbea 100644 --- a/compiler/src/dotty/tools/dotc/typer/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/typer/Inliner.scala @@ -18,7 +18,7 @@ import Names.{Name, TermName} import NameKinds.{InlineAccessorName, InlineBinderName, InlineScrutineeName} import ProtoTypes.selectionProto import SymDenotations.SymDenotation -import Inferencing.fullyDefinedType +import Inferencing.isFullyDefined import config.Printers.inlining import ErrorReporting.errorTree import dotty.tools.dotc.tastyreflect.ReflectionImpl @@ -242,8 +242,10 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { inlining.println(i"-----------------------\nInlining $call\nWith RHS $rhsToInline") - // Make sure all type arguments to the call are fully determined - for (targ <- callTypeArgs) fullyDefinedType(targ.tpe, "inlined type argument", targ.span) + // Make sure all type arguments to the call are fully determined, + // but continue if that's not achievable (or else i7459.scala would crash). + for arg <- callTypeArgs do + isFullyDefined(arg.tpe, ForceDegree.all) /** A map from parameter names of the inlineable method to references of the actual arguments. * For a type argument this is the full argument type. @@ -316,9 +318,9 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { /** Populate `paramBinding` and `bindingsBuf` by matching parameters with * corresponding arguments. `bindingbuf` will be further extended later by - * proxies to this-references. + * proxies to this-references. Issue an error if some arguments are missing. */ - private def computeParamBindings(tp: Type, targs: List[Tree], argss: List[List[Tree]]): Unit = tp match { + private def computeParamBindings(tp: Type, targs: List[Tree], argss: List[List[Tree]]): Boolean = tp match case tp: PolyType => tp.paramNames.lazyZip(targs).foreach { (name, arg) => paramSpan(name) = arg.span @@ -326,19 +328,22 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { } computeParamBindings(tp.resultType, Nil, argss) case tp: MethodType => - assert(argss.nonEmpty, i"missing bindings: $tp in $call") - tp.paramNames.lazyZip(tp.paramInfos).lazyZip(argss.head).foreach { (name, paramtp, arg) => - paramSpan(name) = arg.span - paramBinding(name) = arg.tpe.dealias match { - case _: SingletonType if isIdempotentPath(arg) => arg.tpe - case _ => paramBindingDef(name, paramtp, arg, bindingsBuf).symbol.termRef + if argss.isEmpty then + ctx.error(i"mising arguments for inline method $inlinedMethod", call.sourcePos) + false + else + tp.paramNames.lazyZip(tp.paramInfos).lazyZip(argss.head).foreach { (name, paramtp, arg) => + paramSpan(name) = arg.span + paramBinding(name) = arg.tpe.dealias match { + case _: SingletonType if isIdempotentPath(arg) => arg.tpe + case _ => paramBindingDef(name, paramtp, arg, bindingsBuf).symbol.termRef + } } - } - computeParamBindings(tp.resultType, targs, argss.tail) + computeParamBindings(tp.resultType, targs, argss.tail) case _ => assert(targs.isEmpty) assert(argss.isEmpty) - } + true // Compute val-definitions for all this-proxies and append them to `bindingsBuf` private def computeThisBindings() = { @@ -447,7 +452,8 @@ class Inliner(call: tpd.Tree, rhsToInline: tpd.Tree)(implicit ctx: Context) { } // Compute bindings for all parameters, appending them to bindingsBuf - computeParamBindings(inlinedMethod.info, callTypeArgs, callValueArgss) + if !computeParamBindings(inlinedMethod.info, callTypeArgs, callValueArgss) then + return call // make sure prefix is executed if it is impure if (!isIdempotentExpr(inlineCallPrefix)) registerType(inlinedMethod.owner.thisType) diff --git a/tests/neg/i7438.scala b/tests/neg/i7438.scala new file mode 100644 index 000000000000..c9e74ae31f5a --- /dev/null +++ b/tests/neg/i7438.scala @@ -0,0 +1,9 @@ +type Tr[+A] +inline def (tr: Tr[A]) map[A, B](f: A => B): Tr[B] = ??? + +def (d: Double) func: None.type => Some[Double] = ??? + +def run[A](query: None.type => Some[A]): Some[A] = ??? + +val noBug = run(3.14 func) map (x => x) +val buggy = run(3.14 func map (x => x)) // error: missing parameter type \ No newline at end of file diff --git a/tests/neg/i7459.scala b/tests/neg/i7459.scala new file mode 100644 index 000000000000..e7c99c7a670a --- /dev/null +++ b/tests/neg/i7459.scala @@ -0,0 +1,63 @@ +object Foo { + inline def summon[T](x: T): T = x match { + case t: T => t + } + println(summon) // error +} + +import scala.deriving._ +import scala.compiletime.erasedValue + +inline def summon[T](given t:T): T = t match { + case t: T => t +} + +inline def summonAll[T <: Tuple]: List[Eq[_]] = inline erasedValue[T] match { + case _: Unit => Nil + case _: (t *: ts) => summon[Eq[t]] :: summonAll[ts] // error +} + +trait Eq[T] { + def eqv(x: T, y: T): Boolean +} + +object Eq { + given Eq[Int] { + def eqv(x: Int, y: Int) = x == y + } + + def check(elem: Eq[_])(x: Any, y: Any): Boolean = + elem.asInstanceOf[Eq[Any]].eqv(x, y) + + def iterator[T](p: T) = p.asInstanceOf[Product].productIterator + + def eqSum[T](s: Mirror.SumOf[T], elems: List[Eq[_]]): Eq[T] = + new Eq[T] { + def eqv(x: T, y: T): Boolean = { + val ordx = s.ordinal(x) + (s.ordinal(y) == ordx) && check(elems(ordx))(x, y) + } + } + + def eqProduct[T](p: Mirror.ProductOf[T], elems: List[Eq[_]]): Eq[T] = + new Eq[T] { + def eqv(x: T, y: T): Boolean = + iterator(x).zip(iterator(y)).zip(elems.iterator).forall { + case ((x, y), elem) => check(elem)(x, y) + } + } + + inline given derived[T](given m: Mirror.Of[T]): Eq[T] = { + val elemInstances = summonAll[m.MirroredElemTypes] + inline m match { + case s: Mirror.SumOf[T] => eqSum(s, elemInstances) + case p: Mirror.ProductOf[T] => eqProduct(p, elemInstances) + } + } +} + + +enum Opt[+T] derives Eq { + case Sm(t: T) + case Nn +} \ No newline at end of file diff --git a/tests/pos/matrixOps.scala b/tests/pos/matrixOps.scala new file mode 100644 index 000000000000..1824bc5fbbbf --- /dev/null +++ b/tests/pos/matrixOps.scala @@ -0,0 +1,17 @@ +object Test with + + type Matrix = Array[Array[Double]] + type Vector = Array[Double] + + given (m: Matrix) + def nRows = m.length + def nCols = m(0).length + def row(i: Int): Vector = m(i) + def col(j: Int): Vector = Array.tabulate(m.length)(i => m(i)(j)) + + def pairwise(m: Matrix) = + for + i <- 0 until m.nRows + j <- 0 until m.nCols + yield + m.row(i).zip(m.row(j)).map(_ - _).sum