From d2f07d91db5f0374d798b018086c2ee79b79ad12 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 15 Apr 2024 20:47:55 +0200 Subject: [PATCH 1/5] Fix isAliasType Symbols that had the TypeParam flag set were classified as alias types unless they also had the Deferred flag set. Maybe this did not break that much since Namer always added the Deferred for type parameters. But export forwarders use synthesized parameters which did not have Deferred set. [Cherry-picked 7e1c4ca81b77cc38dd6a34b204ce2a1fba3734f8] --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 3 ++- tests/neg/i20079/Lib_1.scala | 5 +++++ tests/neg/i20079/Test_2.scala | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/neg/i20079/Lib_1.scala create mode 100644 tests/neg/i20079/Test_2.scala diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 53ccb1015115..47c6938afae1 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -688,7 +688,8 @@ object SymDenotations { final def isAbstractType(using Context): Boolean = this.is(DeferredType) /** Is this symbol an alias type? */ - final def isAliasType(using Context): Boolean = isAbstractOrAliasType && !this.is(Deferred) + final def isAliasType(using Context): Boolean = + isAbstractOrAliasType && !isAbstractOrParamType /** Is this symbol an abstract or alias type? */ final def isAbstractOrAliasType: Boolean = isType & !isClass diff --git a/tests/neg/i20079/Lib_1.scala b/tests/neg/i20079/Lib_1.scala new file mode 100644 index 000000000000..6d72042464ce --- /dev/null +++ b/tests/neg/i20079/Lib_1.scala @@ -0,0 +1,5 @@ +object Foo: + def xyz[A, CC[X] <: Iterable[X]](coll: CC[A]): Unit = () + +object Bar: + export Foo.xyz diff --git a/tests/neg/i20079/Test_2.scala b/tests/neg/i20079/Test_2.scala new file mode 100644 index 000000000000..c19d98b55bd8 --- /dev/null +++ b/tests/neg/i20079/Test_2.scala @@ -0,0 +1,6 @@ +object Test: + val ints = List(1) + Foo.xyz[Int, List](ints) + Foo.xyz[Int, scala.collection.View](ints) // error + Bar.xyz[Int, List](ints) + Bar.xyz[Int, scala.collection.View](ints) // error \ No newline at end of file From 92aa2e5c724bb8b4ccbc2cf9255b4f0c61033a66 Mon Sep 17 00:00:00 2001 From: odersky Date: Mon, 15 Apr 2024 22:09:01 +0200 Subject: [PATCH 2/5] Use isAbstractOrParamType more There were some other occurrences of isAbstractType where it was not clear why type parameters should be excluded. Use isAbstractOrParamType as the new default. [Cherry-picked 413c667023fea75dbb84cac625375e0e554c3cea] --- compiler/src/dotty/tools/dotc/cc/CaptureOps.scala | 2 +- compiler/src/dotty/tools/dotc/core/TypeErasure.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Deriving.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Synthesizer.scala | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala index 3ba26c92cab5..efc454b587f6 100644 --- a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala +++ b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala @@ -107,7 +107,7 @@ extension (tp: Type) case tp @ CapturingType(parent, refs) => val pcs = getBoxed(parent) if tp.isBoxed then refs ++ pcs else pcs - case tp: TypeRef if tp.symbol.isAbstractType => CaptureSet.empty + case tp: TypeRef if tp.symbol.isAbstractOrParamType => CaptureSet.empty case tp: TypeProxy => getBoxed(tp.superType) case tp: AndType => getBoxed(tp.tp1) ** getBoxed(tp.tp2) case tp: OrType => getBoxed(tp.tp1) ++ getBoxed(tp.tp2) diff --git a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala index 5832969f9173..3a24d68e5b38 100644 --- a/compiler/src/dotty/tools/dotc/core/TypeErasure.scala +++ b/compiler/src/dotty/tools/dotc/core/TypeErasure.scala @@ -266,7 +266,7 @@ object TypeErasure { tp.paramNames, tp.paramNames map (Function.const(TypeBounds.upper(defn.ObjectType))), tp.resultType) if (defn.isPolymorphicAfterErasure(sym)) eraseParamBounds(sym.info.asInstanceOf[PolyType]) - else if (sym.isAbstractType) TypeAlias(WildcardType) + else if (sym.isAbstractOrParamType) TypeAlias(WildcardType) else if sym.is(ConstructorProxy) then NoType else if (sym.isConstructor) outer.addParam(sym.owner.asClass, erase(tp)(using preErasureCtx)) else if (sym.is(Label)) erase.eraseResult(sym.info)(using preErasureCtx) diff --git a/compiler/src/dotty/tools/dotc/typer/Deriving.scala b/compiler/src/dotty/tools/dotc/typer/Deriving.scala index 818781ae7ccb..8bae343766bf 100644 --- a/compiler/src/dotty/tools/dotc/typer/Deriving.scala +++ b/compiler/src/dotty/tools/dotc/typer/Deriving.scala @@ -31,7 +31,7 @@ trait Deriving { /** A version of Type#underlyingClassRef that works also for higher-kinded types */ private def underlyingClassRef(tp: Type): Type = tp match { case tp: TypeRef if tp.symbol.isClass => tp - case tp: TypeRef if tp.symbol.isAbstractType => NoType + case tp: TypeRef if tp.symbol.isAbstractOrParamType => NoType case tp: TermRef => NoType case tp: TypeProxy => underlyingClassRef(tp.superType) case _ => NoType diff --git a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala index 264850548b02..c623f4f9fd8a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -657,7 +657,7 @@ class Synthesizer(typer: Typer)(using @constructorOnly c: Context): def canManifest(tp: Manifestable, topLevel: Boolean) = val sym = tp.typeSymbol - !sym.isAbstractType + !sym.isAbstractOrParamType && hasStableErasure(tp) && !(topLevel && defn.isBottomClassAfterErasure(sym)) From 21ebb62af81e2f0eebd5d5907ee755065be64115 Mon Sep 17 00:00:00 2001 From: odersky Date: Tue, 16 Apr 2024 11:47:58 +0200 Subject: [PATCH 3/5] Avoid adding redundant Deferred flag to type parameters in Namer [Cherry-picked a78214865a5613da682d1d517f6ec3b412b05861] --- compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala | 2 +- compiler/src/dotty/tools/dotc/typer/Namer.scala | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala index d088b2f6fca0..6c4e86c573cf 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -445,7 +445,7 @@ private class ExtractAPICollector(using Context) extends ThunkHolder { if (sym.isAliasType) api.TypeAlias.of(name, access, modifiers, as.toArray, typeParams, apiType(tpe.bounds.hi)) else { - assert(sym.isAbstractType) + assert(sym.isAbstractOrParamType) api.TypeDeclaration.of(name, access, modifiers, as.toArray, typeParams, apiType(tpe.bounds.lo), apiType(tpe.bounds.hi)) } } diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index ea6d65f65416..077b10526bac 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -271,7 +271,7 @@ class Namer { typer: Typer => analyzeRHS(body) case _ => if rhs.isEmpty || flags.is(Opaque) then flags |= Deferred - analyzeRHS(tree.rhs) + if flags.is(Param) then tree.rhs else analyzeRHS(tree.rhs) // to complete a constructor, move one context further out -- this // is the context enclosing the class. Note that the context in which a From 370cdc16128b979796f7cd037982c87822f5fddb Mon Sep 17 00:00:00 2001 From: odersky Date: Tue, 16 Apr 2024 13:21:09 +0200 Subject: [PATCH 4/5] Drop isAbstractType Always use isAbstractorParamType. quotes.reflect still uses isAbstractType for backwards compatibility, but it now also includes type parameters. This was the case anyway before for type parameters set up by Namer. [Cherry-picked aaacc439c6797e4d04004c9e34147b06d03e9afa] --- compiler/src/dotty/tools/dotc/core/SymDenotations.scala | 3 --- compiler/src/dotty/tools/dotc/core/Types.scala | 2 +- compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala | 2 +- library/src/scala/quoted/Quotes.scala | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala index 47c6938afae1..71e54132f0ef 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -684,9 +684,6 @@ object SymDenotations { def isWrappedToplevelDef(using Context): Boolean = !isConstructor && owner.isPackageObject - /** Is this symbol an abstract type? */ - final def isAbstractType(using Context): Boolean = this.is(DeferredType) - /** Is this symbol an alias type? */ final def isAliasType(using Context): Boolean = isAbstractOrAliasType && !isAbstractOrParamType diff --git a/compiler/src/dotty/tools/dotc/core/Types.scala b/compiler/src/dotty/tools/dotc/core/Types.scala index bd867c9370c0..25c18698fe47 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2571,7 +2571,7 @@ object Types extends TypeUtils { symd.maybeOwner.membersNeedAsSeenFrom(prefix) && !symd.is(NonMember) || prefix.match case prefix: Types.ThisType => - (symd.isAbstractType + (symd.isAbstractOrParamType || symd.isTerm && !symd.flagsUNSAFE.isOneOf(Module | Final | Param) && !symd.isConstructor diff --git a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala index 59c56c8f676b..16df7d096192 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -2649,7 +2649,7 @@ class QuotesImpl private (using val ctx: Context) extends Quotes, QuoteUnpickler def isAliasType: Boolean = self.denot.isAliasType def isAnonymousClass: Boolean = self.denot.isAnonymousClass def isAnonymousFunction: Boolean = self.denot.isAnonymousFunction - def isAbstractType: Boolean = self.denot.isAbstractType + def isAbstractType: Boolean = self.denot.isAbstractOrParamType def isClassConstructor: Boolean = self.denot.isClassConstructor def isType: Boolean = self.isType def isTerm: Boolean = self.isTerm diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index 8d1c8b8f4921..873d5e1e993e 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -3993,7 +3993,7 @@ trait Quotes { self: runtime.QuoteUnpickler & runtime.QuoteMatching => /** Is this symbol an anonymous function? */ def isAnonymousFunction: Boolean - /** Is this symbol an abstract type? */ + /** Is this symbol an abstract type or a type parameter? */ def isAbstractType: Boolean /** Is this the constructor of a class? */ From af95a3827ea6b31d58c8340f9c4e45d65cc0c0eb Mon Sep 17 00:00:00 2001 From: Wojciech Mazur Date: Sat, 6 Jul 2024 12:34:17 +0200 Subject: [PATCH 5/5] Drop redundant `butNot = Param` clause in isAnchor [Cherry-picked 9d88c800ba518b184bb5f63259a782532d1abf96][modified] --- compiler/src/dotty/tools/dotc/typer/Implicits.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dotty/tools/dotc/typer/Implicits.scala b/compiler/src/dotty/tools/dotc/typer/Implicits.scala index 92d077c9199e..85458a2fae7d 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -596,7 +596,7 @@ trait ImplicitRunInfo: private def isAnchor(sym: Symbol) = sym.isClass && !isExcluded(sym) || sym.isOpaqueAlias - || sym.is(Deferred, butNot = Param) + || sym.is(Deferred) || sym.info.isInstanceOf[MatchAlias] private def computeIScope(rootTp: Type): OfTypeImplicits =