diff --git a/community-build/community-projects/zio b/community-build/community-projects/zio index 25977ff09847..912b4f887912 160000 --- a/community-build/community-projects/zio +++ b/community-build/community-projects/zio @@ -1 +1 @@ -Subproject commit 25977ff09847f1e7857f799e0abaf00c82003e76 +Subproject commit 912b4f887912792202aa76e93fd19e63bd62f3bc diff --git a/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala b/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala index 7be63fc8ba3a..b5e2e7d475ad 100644 --- a/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala +++ b/compiler/src/dotty/tools/dotc/inlines/InlineReducer.scala @@ -14,7 +14,7 @@ import util.SimpleIdentityMap import collection.mutable -/** A utility object offering methods for rewriting inlined code */ +/** A utility class offering methods for rewriting inlined code */ class InlineReducer(inliner: Inliner)(using Context): import tpd.* import Inliner.{isElideableExpr, DefBuffer} diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index dda4b89f6d1c..2b72b6c8bdbd 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -14,6 +14,7 @@ import Decorators._ import Symbols._, SymUtils._, NameOps._ import ContextFunctionResults.annotateContextResults import config.Printers.typr +import util.SrcPos import reporting._ object PostTyper { @@ -342,7 +343,14 @@ class PostTyper extends MacroTransform with IdentityDenotTransformer { thisPhase if tree.symbol.is(Inline) then ctx.compilationUnit.needsInlining = true val tree1 @ TypeApply(fn, args) = normalizeTypeArgs(tree) - args.foreach(checkInferredWellFormed) + for arg <- args do + checkInferredWellFormed(arg) + val isInferred = arg.isInstanceOf[InferredTypeTree] || arg.span.isSynthetic + if !isInferred then + // only check explicit type arguments. We rely on inferred type arguments + // to either have good bounds (if they come from a constraint), or be derived + // from values that recursively need to have good bounds. + Checking.checkGoodBounds(arg.tpe, arg.srcPos) if (fn.symbol != defn.ChildAnnot.primaryConstructor) // Make an exception for ChildAnnot, which should really have AnyKind bounds Checking.checkBounds(args, fn.tpe.widen.asInstanceOf[PolyType]) diff --git a/compiler/src/dotty/tools/dotc/typer/Checking.scala b/compiler/src/dotty/tools/dotc/typer/Checking.scala index c636510fdb89..45302f476d48 100644 --- a/compiler/src/dotty/tools/dotc/typer/Checking.scala +++ b/compiler/src/dotty/tools/dotc/typer/Checking.scala @@ -73,10 +73,11 @@ object Checking { showInferred(MissingTypeParameterInTypeApp(arg.tpe), app, tpt)) } for (arg, which, bound) <- TypeOps.boundsViolations(args, boundss, instantiate, app) do - report.error( - showInferred(DoesNotConformToBound(arg.tpe, which, bound), - app, tpt), - arg.srcPos.focus) + if checkGoodBounds(arg.tpe, arg.srcPos.focus) then + report.error( + showInferred(DoesNotConformToBound(arg.tpe, which, bound), + app, tpt), + arg.srcPos.focus) /** Check that type arguments `args` conform to corresponding bounds in `tl` * Note: This does not check the bounds of AppliedTypeTrees. These @@ -85,6 +86,18 @@ object Checking { def checkBounds(args: List[tpd.Tree], tl: TypeLambda)(using Context): Unit = checkBounds(args, tl.paramInfos, _.substParams(tl, _)) + def checkGoodBounds(tpe: Type, pos: SrcPos)(using Context): Boolean = + def recur(tp: Type) = tp.dealias match + case tp: TypeRef => + checkGoodBounds(tp.info, pos) + case TypeBounds(lo, hi) if !(lo <:< hi) => + val argStr = if tp eq tpe then "" else i" $tpe" + report.error(i"type argument$argStr has potentially unrealizable bounds $tp", pos) + false + case _ => + true + recur(tpe) + /** Check applied type trees for well-formedness. This means * - all arguments are within their corresponding bounds * - if type is a higher-kinded application with wildcard arguments, diff --git a/tests/neg/i15568.check b/tests/neg/i15568.check new file mode 100644 index 000000000000..3a988433d074 --- /dev/null +++ b/tests/neg/i15568.check @@ -0,0 +1,4 @@ +-- Error: tests/neg/i15568.scala:3:15 ---------------------------------------------------------------------------------- +3 |type Bar = Foo[? >: Int <: String] // error + | ^ + | type argument has potentially unrealizable bounds >: Int <: String diff --git a/tests/neg/i15568.scala b/tests/neg/i15568.scala new file mode 100644 index 000000000000..422713b6a0bc --- /dev/null +++ b/tests/neg/i15568.scala @@ -0,0 +1,3 @@ +trait Foo[X >: Int <: String] + +type Bar = Foo[? >: Int <: String] // error diff --git a/tests/neg/i15569.scala b/tests/neg/i15569.scala new file mode 100644 index 000000000000..f98345a61691 --- /dev/null +++ b/tests/neg/i15569.scala @@ -0,0 +1,15 @@ +trait Foo[X >: Any <: Nothing] + +def andThenSub[A, B, C](f: A <:< B, g: B <:< C): A <:< C = + f.andThen(g) + +@main def Test = (None: Option[Foo[?]]) match { + case _: Option[Foo[t]] => + val unsound: Any <:< Nothing = andThenSub[Any, t, Nothing](summon, summon) // error + unsound("hi :)") +} +@main def Test2 = + type t >: Any <: Nothing + val unsound: Any <:< Nothing = andThenSub[Any, t, Nothing](summon, summon) // error + unsound("hi :)") +