From 7e1c4ca81b77cc38dd6a34b204ce2a1fba3734f8 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. --- 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 bfaaf78883ae..9c6aba1b30b8 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -689,7 +689,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 413c667023fea75dbb84cac625375e0e554c3cea 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. --- 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 1c951a0c0846..8100f78e50e7 100644 --- a/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala +++ b/compiler/src/dotty/tools/dotc/cc/CaptureOps.scala @@ -150,7 +150,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 0474aff4087a..b4d2934fb04b 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 f3be1dcff766..619dfcf4d7cb 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 d244af12dd91..192fdd404aba 100644 --- a/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Synthesizer.scala @@ -671,7 +671,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 a78214865a5613da682d1d517f6ec3b412b05861 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 --- 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 138cda099040..50825907be43 100644 --- a/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala +++ b/compiler/src/dotty/tools/dotc/sbt/ExtractAPI.scala @@ -564,7 +564,7 @@ private class ExtractAPICollector(nonLocalClassSymbols: mutable.HashSet[Symbol]) 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 1016fe467a0a..db015846391c 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -274,7 +274,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 aaacc439c6797e4d04004c9e34147b06d03e9afa 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. --- 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 9c6aba1b30b8..73190991a2c1 100644 --- a/compiler/src/dotty/tools/dotc/core/SymDenotations.scala +++ b/compiler/src/dotty/tools/dotc/core/SymDenotations.scala @@ -685,9 +685,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 47ba9833fc2f..ed66ecc2d498 100644 --- a/compiler/src/dotty/tools/dotc/core/Types.scala +++ b/compiler/src/dotty/tools/dotc/core/Types.scala @@ -2700,7 +2700,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 81fadb6baa89..f98147cf5052 100644 --- a/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala +++ b/compiler/src/scala/quoted/runtime/impl/QuotesImpl.scala @@ -2687,7 +2687,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 isSuperAccessor = self.name.is(dotc.core.NameKinds.SuperAccessorName) def isType: Boolean = self.isType diff --git a/library/src/scala/quoted/Quotes.scala b/library/src/scala/quoted/Quotes.scala index b49763c38221..1bb8405662ac 100644 --- a/library/src/scala/quoted/Quotes.scala +++ b/library/src/scala/quoted/Quotes.scala @@ -4025,7 +4025,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 9d88c800ba518b184bb5f63259a782532d1abf96 Mon Sep 17 00:00:00 2001 From: odersky Date: Tue, 16 Apr 2024 13:21:41 +0200 Subject: [PATCH 5/5] Drop redundant `butNot = Param` clause in isAnchor --- 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 5ffc81744d85..f4545db81e9a 100644 --- a/compiler/src/dotty/tools/dotc/typer/Implicits.scala +++ b/compiler/src/dotty/tools/dotc/typer/Implicits.scala @@ -621,7 +621,7 @@ trait ImplicitRunInfo: private def isAnchor(sym: Symbol) = sym.isClass && !isExcluded(sym) || sym.isOpaqueAlias - || sym.is(Deferred, butNot = Param) + || sym.is(Deferred) || sym.info.isMatchAlias private def computeIScope(rootTp: Type): OfTypeImplicits =