diff --git a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala index 500df14fdb1f..d380dcbf3dd1 100644 --- a/compiler/src/dotty/tools/dotc/parsing/Parsers.scala +++ b/compiler/src/dotty/tools/dotc/parsing/Parsers.scala @@ -2176,9 +2176,9 @@ object Parsers { in.endMarkerScope(NEW) { val start = in.skipToken() def reposition(t: Tree) = t.withSpan(Span(start, in.lastOffset)) - possibleBracesStart() + possibleTemplateStart() val parents = - if in.token == LBRACE then Nil + if in.isNestedStart then Nil else constrApps(commaOK = false, templateCanFollow = true) colonAtEOLOpt() possibleTemplateStart(isNew = true) diff --git a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala index b03ace7f8d50..b74ad17a1311 100644 --- a/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala +++ b/compiler/src/dotty/tools/dotc/typer/ErrorReporting.scala @@ -89,7 +89,6 @@ object ErrorReporting { if (tree.tpe.widen.exists) i"${exprStr(tree)} does not take ${kind}parameters" else { - if (ctx.settings.Ydebug.value) new FatalError("").printStackTrace() i"undefined: $tree # ${tree.uniqueId}: ${tree.tpe.toString} at ${ctx.phase}" } diff --git a/compiler/src/dotty/tools/dotc/typer/Nullables.scala b/compiler/src/dotty/tools/dotc/typer/Nullables.scala index f66f5e996b90..544c8b49ec98 100644 --- a/compiler/src/dotty/tools/dotc/typer/Nullables.scala +++ b/compiler/src/dotty/tools/dotc/typer/Nullables.scala @@ -464,7 +464,8 @@ object Nullables with */ def postProcessByNameArgs(fn: TermRef, app: Tree)(given ctx: Context): Tree = fn.widen match - case mt: MethodType if mt.paramInfos.exists(_.isInstanceOf[ExprType]) => + case mt: MethodType + if mt.paramInfos.exists(_.isInstanceOf[ExprType]) && !fn.symbol.is(Inline) => app match case Apply(fn, args) => val dropNotNull = new TreeMap with @@ -487,10 +488,10 @@ object Nullables with case _ => super.typedUnadapted(t, pt, locked) def postProcess(formal: Type, arg: Tree): Tree = - val arg1 = dropNotNull.transform(arg) + val nestedCtx = ctx.fresh.setNewTyperState() + val arg1 = dropNotNull.transform(arg)(given nestedCtx) if arg1 eq arg then arg else - val nestedCtx = ctx.fresh.setNewTyperState() val arg2 = retyper.typed(arg1, formal)(given nestedCtx) if nestedCtx.reporter.hasErrors || !(arg2.tpe <:< formal) then ctx.error(em"""This argument was typed using flow assumptions about mutable variables @@ -506,7 +507,10 @@ object Nullables with def recur(formals: List[Type], args: List[Tree]): List[Tree] = (formals, args) match case (formal :: formalsRest, arg :: argsRest) => - val arg1 = postProcess(formal.widenExpr.repeatedToSingle, arg) + val arg1 = + if formal.isInstanceOf[ExprType] + then postProcess(formal.widenExpr.repeatedToSingle, arg) + else arg val argsRest1 = recur( if formal.isRepeatedParam then formals else formalsRest, argsRest) diff --git a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala index 09cf453e483e..d31e2b6c1bfd 100644 --- a/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala +++ b/compiler/src/dotty/tools/dotc/typer/TypeAssigner.scala @@ -411,6 +411,7 @@ trait TypeAssigner { else errorType(i"wrong number of arguments at ${ctx.phase.prev} for $fntpe: ${fn.tpe}, expected: ${fntpe.paramInfos.length}, found: ${args.length}", tree.sourcePos) case t => + if (ctx.settings.Ydebug.value) new FatalError("").printStackTrace() errorType(err.takesNoParamsStr(fn, ""), tree.sourcePos) } ConstFold(tree.withType(ownType)) diff --git a/tests/neg-custom-args/explicit-nulls/byname-nullables1.check b/tests/neg-custom-args/explicit-nulls/byname-nullables1.check new file mode 100644 index 000000000000..e4a46bf8322f --- /dev/null +++ b/tests/neg-custom-args/explicit-nulls/byname-nullables1.check @@ -0,0 +1,8 @@ +-- Error: tests/neg-custom-args/explicit-nulls/byname-nullables1.scala:10:6 -------------------------------------------- +10 | f(x.fld != null) // error + | ^^^^^^^^^^^^^ + | This argument was typed using flow assumptions about mutable variables + | but it is passed to a by-name parameter where such flow assumptions are unsound. + | Wrapping the argument in `byName(...)` fixes the problem by disabling the flow assumptions. + | + | `byName` needs to be imported from the `scala.compiletime` package. diff --git a/tests/neg-custom-args/explicit-nulls/byname-nullables1.scala b/tests/neg-custom-args/explicit-nulls/byname-nullables1.scala new file mode 100644 index 000000000000..eb28a5af96c0 --- /dev/null +++ b/tests/neg-custom-args/explicit-nulls/byname-nullables1.scala @@ -0,0 +1,11 @@ +def f(op: => Boolean): Unit = () +def f(op: Int): Unit = () + +class C with + var fld: String | Null = null + +def test() = + var x: C | Null = C() + if x != null then + f(x.fld != null) // error + require(x.fld != null, "error") // ok \ No newline at end of file diff --git a/tests/neg/new-with.scala b/tests/pos/new-with.scala similarity index 100% rename from tests/neg/new-with.scala rename to tests/pos/new-with.scala diff --git a/tests/run/LazyLists.scala b/tests/run/LazyLists.scala new file mode 100644 index 000000000000..51e648104388 --- /dev/null +++ b/tests/run/LazyLists.scala @@ -0,0 +1,109 @@ +package xcollections with + import annotation.unchecked.uncheckedVariance + + abstract class LazyList[+T] with + + private var myHead: T = _ + private var myTail: LazyList[T] = _ + private var myForced: LazyList[T] | Null = null + + protected def force(): LazyList[T] + + protected def set(hd: T @uncheckedVariance, tl: LazyList[T] @uncheckedVariance): LazyList[T] = + assert(myForced == null, "implementation error: attempting to re-define existing LazyList") + myHead = hd + myTail = tl + this + + def forced(): LazyList[T] = + var myForced = this.myForced + if myForced == null then + myForced = force() + this.myForced = myForced + assert(myForced.myForced != null, "implementation error: LazyList was not forced") + myForced + else myForced + + def isEmpty: Boolean = forced() eq LazyList.empty + + def head: T = + val e = forced() + require(!e.isEmpty, "head on empty LazyList") + e.myHead + + def tail: LazyList[T] = + val e = forced() + require(!e.isEmpty, "tail on empty LazyList") + e.myTail + + def fromIterable[T](xs: Iterable[T]) = xs match + case xs: LazyList[T] @unchecked => xs + case _ => LazyList.fromIterator(xs.iterator) + + object LazyList with + + val empty: LazyList[Nothing] = new with + protected def force(): LazyList[Nothing] = this + + object #:: with + def unapply[T](xs: LazyList[T]): Option[(T, LazyList[T])] = + if xs.isEmpty then None + else Some((xs.head, xs.tail)) + + def fromIterator[T](it: Iterator[T]): LazyList[T] = new with + protected def force() = + if it.hasNext then set(it.next, fromIterator (it)) + else empty + + given [T, U >: T](xs: LazyList[T]) extended with + + def #::(x: U): LazyList[U] = new with + protected def force(): LazyList[U] = + set(x, xs) + + def ++(ys: LazyList[U]): LazyList[U] = new with + protected def force() = + if xs.isEmpty then ys.forced() + else set(xs.head, xs.tail ++ ys) + + given [T, U](xs: LazyList[T]) extended with + def map(f: T => U): LazyList[U] = new with + protected def force() = + if xs.isEmpty then empty + else set(f(xs.head), xs.tail.map(f)) + + def flatMap(f: T => LazyList[U]): LazyList[U] = new with + protected def force(): LazyList[U] = + if xs.isEmpty then empty + else f(xs.head) ++ xs.tail.flatMap(f) + + def foldLeft(z: U)(f: (U, T) => U): U = + if xs.isEmpty then z + else xs.tail.foldLeft(f(z, xs.head))(f) + + given [T](xs: LazyList[T]) extended with + def filter(p: T => Boolean): LazyList[T] = new with + protected def force(): LazyList[T] = + if xs.isEmpty then empty + else if p(xs.head) then set(xs.head, xs.tail.filter(p)) + else xs.tail.filter(p) + + def take(n: Int): LazyList[T] = + if n <= 0 then empty + else new with + protected def force(): LazyList[T] = + if xs.isEmpty then xs + else set(xs.head, xs.tail.take(n - 1)) + + def drop(n: Int): LazyList[T] = + if n <= 0 then xs + else new with + protected def force(): LazyList[T] = + def advance(xs: LazyList[T], n: Int): LazyList[T] = + if n <= 0 || xs.isEmpty then xs + else advance(xs.tail, n - 1) + advance(xs, n) + end LazyList +end xcollections + +@main def Test() = () \ No newline at end of file