diff --git a/changelogs/3.7.1-RC1.md b/changelogs/3.7.1-RC1.md new file mode 100644 index 000000000000..8f61c0d2bf32 --- /dev/null +++ b/changelogs/3.7.1-RC1.md @@ -0,0 +1,157 @@ +# Highlights of the release + +- Support for JDK 25 [#23004](https://github.com/scala/scala3/pull/23004) +- Warn if interpolator uses toString [#20578](https://github.com/scala/scala3/pull/20578) +- Warn if match in block is not used for PartialFunction [#23002](https://github.com/scala/scala3/pull/23002) + +# Other changes and fixes + +## Annotations + +- Approximate annotated types in `wildApprox` [#22893](https://github.com/scala/scala3/pull/22893) +- Keep unused annot on params [#23037](https://github.com/scala/scala3/pull/23037) + +## Erasure + +- Disallow context function types as value-class parameters [#23015](https://github.com/scala/scala3/pull/23015) + +## Experimental: Capture Checking + +- Two fixes to handling of abstract types with cap bounds [#22838](https://github.com/scala/scala3/pull/22838) +- Drop idempotent type maps [#22910](https://github.com/scala/scala3/pull/22910) +- Fix setup of class constructors [#22980](https://github.com/scala/scala3/pull/22980) + +## Named Tuples + +- Call dealias after stripping type variables for tupleElementTypesUpTo [#23005](https://github.com/scala/scala3/pull/23005) +- Avoid loosing denotations of named types during `integrate` [#22839](https://github.com/scala/scala3/pull/22839) + +## Experimental: Unroll + +- Fix #22833: allow unroll annotation in methods of final class [#22926](https://github.com/scala/scala3/pull/22926) + +## Experimental: Referencable Package Objects + +- Add experimental.packageObjectValues language setting [#23001](https://github.com/scala/scala3/pull/23001) + +## Exports + +- Respect export alias for default arg forwarder [#21109](https://github.com/scala/scala3/pull/21109) + +## Extension Methods + +- Extension check checks for no parens not empty parens [#22825](https://github.com/scala/scala3/pull/22825) + +## GADTs + +- Fix: Prevent GADT reasoning in pattern alternatives [#22853](https://github.com/scala/scala3/pull/22853) + +## Linting + +- Dealias when looking into imports [#22889](https://github.com/scala/scala3/pull/22889) +- Process Export for unused check [#22984](https://github.com/scala/scala3/pull/22984) +- Drill into QuotePattern bindings symbol info [#22987](https://github.com/scala/scala3/pull/22987) +- No warn implicit param of overriding method [#22901](https://github.com/scala/scala3/pull/22901) +- No warn for evidence params of marker traits such as NotGiven [#22985](https://github.com/scala/scala3/pull/22985) + +## Initialization + +- Check for tasty error in template trees. [#22867](https://github.com/scala/scala3/pull/22867) + +## Metaprogramming: Compile-time + +- Fix issue with certain synthetics missing in compiletime.typechecks [#22978](https://github.com/scala/scala3/pull/22978) + +## Pattern Matching + +- Fix existing GADT constraints with introduced pattern-bound symbols [#22928](https://github.com/scala/scala3/pull/22928) + +## Pickling + +- Fix fromProduct synthesized code for parameter-dependent case classes [#22961](https://github.com/scala/scala3/pull/22961) + +## Presentation Compiler + +- Completions for requests just before string [#22894](https://github.com/scala/scala3/pull/22894) +- Fix: go to def should lead to all: apply, object and class [#22771](https://github.com/scala/scala3/pull/22771) +- Ignore ending `$` when looking at end marker names [#22798](https://github.com/scala/scala3/pull/22798) +- Feature: Skip auto importing symbols we know are wrong in current context [#22813](https://github.com/scala/scala3/pull/22813) +- Show the Autofill completion case as what would be auto-filled [#22819](https://github.com/scala/scala3/pull/22819) +- Bugfix: Fix issues with annotations not detected [#22878](https://github.com/scala/scala3/pull/22878) +- Improvement: Rework IndexedContext to reuse the previously calculated scopes [#22898](https://github.com/scala/scala3/pull/22898) +- Pc: Properly adjust indentation when inlining blocks [#22915](https://github.com/scala/scala3/pull/22915) +- Improvement: Support using directives in worksheets [#22957](https://github.com/scala/scala3/pull/22957) +- Fix: show hover for synthetics if explicitly used [#22973](https://github.com/scala/scala3/pull/22973) +- Pc: fix: inline value when def indentation equals 2 [#22990](https://github.com/scala/scala3/pull/22990) + +## Rewrites + +- Fix insertion of `using` in applications with trailing lambda syntax [#22937](https://github.com/scala/scala3/pull/22937) +- Test chars safely when highlighting [#22918](https://github.com/scala/scala3/pull/22918) + +## Reporting + +- Print infix operations in infix form [#22854](https://github.com/scala/scala3/pull/22854) + +## Scaladoc + +- Chore: add support for 'abstract override' modifier [#22802](https://github.com/scala/scala3/pull/22802) +- Scaladoc: fix generation of unique header ids [#22779](https://github.com/scala/scala3/pull/22779) + +## Typer + +- Disallow context bounds in type lambdas [#22659](https://github.com/scala/scala3/pull/22659) +- Refuse trailing type parameters in extractors [#22699](https://github.com/scala/scala3/pull/22699) +- Fix #22724: Revert the PolyType case in #21744 [#22820](https://github.com/scala/scala3/pull/22820) +- Fix isGenericArrayElement for higher-kinded types [#22938](https://github.com/scala/scala3/pull/22938) +- Tighten condition to preserve denotation in IntegrateMap [#23060](https://github.com/scala/scala3/pull/23060) + +## Transform + +- Mix in the `productPrefix` hash statically in case class `hashCode` [#22865](https://github.com/scala/scala3/pull/22865) + +## Value Classes + +- Fix #21918: Disallow value classes extending type aliases of AnyVal [#23021](https://github.com/scala/scala3/pull/23021) + + +# Contributors + +Thank you to all the contributors who made this release possible 🎉 + +According to `git shortlog -sn --no-merges 3.7.0..3.7.1-RC1` these are: + +``` + 135 Martin Odersky + 27 Som Snytt + 13 Matt Bovel + 10 Wojciech Mazur + 9 Hamza Remmal + 5 Quentin Bernet + 5 Tomasz Godzik + 4 aherlihy + 3 HarrisL2 + 3 Jan Chyb + 3 Natsu Kagami + 3 Ondrej Lhotak + 3 Sébastien Doeraene + 2 Piotr Chabelski + 2 Yichen Xu + 2 Yoonjae Jeon + 2 kasiaMarek + 1 Aleksey Troitskiy + 1 Daisy Li + 1 Dale Wijnand + 1 Jan-Pieter van den Heuvel + 1 Jędrzej Rochala + 1 Kacper Korban + 1 Katarzyna Marek + 1 Lukas Rytz + 1 Mikołaj Fornal + 1 Nikita Glushchenko + 1 Oliver Bračevac + 1 Ondřej Lhoták + 1 dependabot[bot] + 1 noti0na1 + 1 philippus +``` diff --git a/changelogs/3.7.1-RC2.md b/changelogs/3.7.1-RC2.md new file mode 100644 index 000000000000..6a9b9d88bb79 --- /dev/null +++ b/changelogs/3.7.1-RC2.md @@ -0,0 +1,25 @@ +# Backported chnages + +- Backport "chore: filter allowed source versions by import and by settings" to 3.7.1 (#23231) +- Backport "Bump Scala CLI to v1.8.0 (was v1.7.1)" to 3.7.1 (#23230) +- Backport "Mention extension in unused param warning" to 3.7.1 (#23229) +- Backport "Revert recent changes to opaque type proxy generation" to 3.7.1 (#23228) +- Backport "Remove premature caching of lookups for unused lint" to 3.7.1 (#23227) + +# Reverted changes + +- Revert "Make overload pruning based on result types less aggressive (#21744)" in 3.7.1-RC2 (#23239) + +# Contributors + +Thank you to all the contributors who made this release possible 🎉 + +According to `git shortlog -sn --no-merges 3.7.1-RC1..3.7.1-RC2` these are: + +``` + 4 Hamza Remmal + 4 Som Snytt + 3 Jan Chyb + 3 Wojciech Mazur + 1 Piotr Chabelski +``` diff --git a/compiler/src/dotty/tools/dotc/ast/Desugar.scala b/compiler/src/dotty/tools/dotc/ast/Desugar.scala index 471a9953c4f0..2c30896105b2 100644 --- a/compiler/src/dotty/tools/dotc/ast/Desugar.scala +++ b/compiler/src/dotty/tools/dotc/ast/Desugar.scala @@ -703,7 +703,7 @@ object desugar { def isNonEnumCase = !isEnumCase && (isCaseClass || isCaseObject) val isValueClass = parents.nonEmpty && isAnyVal(parents.head) // This is not watertight, but `extends AnyVal` will be replaced by `inline` later. - val caseClassInScala2Library = isCaseClass && ctx.settings.YcompileScala2Library.value + val caseClassInScala2Library = isCaseClass && Feature.shouldBehaveAsScala2 val originalTparams = constr1.leadingTypeParams val originalVparamss = asTermOnly(constr1.trailingParamss) @@ -922,7 +922,7 @@ object desugar { val copyRestParamss = derivedVparamss.tail.nestedMap(vparam => cpy.ValDef(vparam)(rhs = EmptyTree)) var flags = Synthetic | constr1.mods.flags & copiedAccessFlags - if ctx.settings.YcompileScala2Library.value then flags &~= Private + if Feature.shouldBehaveAsScala2 then flags &~= Private DefDef( nme.copy, joinParams(derivedTparams, copyFirstParams :: copyRestParamss), @@ -983,7 +983,7 @@ object desugar { else { val appMods = var flags = Synthetic | constr1.mods.flags & copiedAccessFlags - if ctx.settings.YcompileScala2Library.value then flags &~= Private + if Feature.shouldBehaveAsScala2 then flags &~= Private Modifiers(flags).withPrivateWithin(constr1.mods.privateWithin) val appParamss = derivedVparamss.nestedZipWithConserve(constrVparamss)((ap, cp) => @@ -1066,7 +1066,7 @@ object desugar { paramss // drop leading () that got inserted by class // TODO: drop this once we do not silently insert empty class parameters anymore case paramss => paramss - val finalFlag = if ctx.settings.YcompileScala2Library.value then EmptyFlags else Final + val finalFlag = if Feature.shouldBehaveAsScala2 then EmptyFlags else Final // implicit wrapper is typechecked in same scope as constructor, so // we can reuse the constructor parameters; no derived params are needed. DefDef( diff --git a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala index 45e17794ec96..0f0165ce859e 100644 --- a/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala +++ b/compiler/src/dotty/tools/dotc/ast/TreeInfo.scala @@ -9,6 +9,7 @@ import Annotations.Annotation import NameKinds.ContextBoundParamName import typer.ConstFold import reporting.trace +import config.Feature import Decorators.* import Constants.Constant @@ -466,7 +467,7 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] */ private def defKind(tree: Tree)(using Context): FlagSet = unsplice(tree) match { case EmptyTree | _: Import => NoInitsInterface - case tree: TypeDef if ctx.settings.YcompileScala2Library.value => + case tree: TypeDef if Feature.shouldBehaveAsScala2 => if (tree.isClassDef) EmptyFlags else NoInitsInterface case tree: TypeDef => if (tree.isClassDef) NoInits else NoInitsInterface case tree: DefDef => @@ -479,7 +480,7 @@ trait UntypedTreeInfo extends TreeInfo[Untyped] { self: Trees.Instance[Untyped] NoInitsInterface else if tree.mods.is(Given) && tree.paramss.isEmpty then EmptyFlags // might become a lazy val: TODO: check whether we need to suppress NoInits once we have new lazy val impl - else if ctx.settings.YcompileScala2Library.value then + else if Feature.shouldBehaveAsScala2 then EmptyFlags else NoInits diff --git a/compiler/src/dotty/tools/dotc/config/Feature.scala b/compiler/src/dotty/tools/dotc/config/Feature.scala index a53346c8a44d..8fda99be6896 100644 --- a/compiler/src/dotty/tools/dotc/config/Feature.scala +++ b/compiler/src/dotty/tools/dotc/config/Feature.scala @@ -154,6 +154,10 @@ object Feature: case Some(v) => v case none => sourceVersionSetting + /* Should we behave as scala 2?*/ + def shouldBehaveAsScala2(using Context): Boolean = + ctx.settings.YcompileScala2Library.value || sourceVersion.isScala2 + def migrateTo3(using Context): Boolean = sourceVersion == `3.0-migration` diff --git a/compiler/src/dotty/tools/dotc/config/ScalaSettingsProperties.scala b/compiler/src/dotty/tools/dotc/config/ScalaSettingsProperties.scala index e42d2d53529e..12de678d6df2 100644 --- a/compiler/src/dotty/tools/dotc/config/ScalaSettingsProperties.scala +++ b/compiler/src/dotty/tools/dotc/config/ScalaSettingsProperties.scala @@ -25,7 +25,8 @@ object ScalaSettingsProperties: ScalaRelease.values.toList.map(_.show) def supportedSourceVersions: List[String] = - (SourceVersion.values.toList.diff(SourceVersion.illegalSourceVersionNames)).toList.map(_.toString) + SourceVersion.values.diff(SourceVersion.illegalInSettings) + .map(_.toString).toList def supportedLanguageFeatures: List[ChoiceWithHelp[String]] = Feature.values.map((n, d) => ChoiceWithHelp(n.toString, d)) diff --git a/compiler/src/dotty/tools/dotc/config/SourceVersion.scala b/compiler/src/dotty/tools/dotc/config/SourceVersion.scala index 30a88fb79f2a..d662d3c0d412 100644 --- a/compiler/src/dotty/tools/dotc/config/SourceVersion.scala +++ b/compiler/src/dotty/tools/dotc/config/SourceVersion.scala @@ -8,7 +8,8 @@ import Feature.isPreviewEnabled import util.Property enum SourceVersion: - case `3.0-migration`, `3.0`, `3.1` // Note: do not add `3.1-migration` here, 3.1 is the same language as 3.0. + case `3.0-migration`, `3.0` + case `3.1-migration`, `3.1` case `3.2-migration`, `3.2` case `3.3-migration`, `3.3` case `3.4-migration`, `3.4` @@ -16,7 +17,9 @@ enum SourceVersion: case `3.6-migration`, `3.6` case `3.7-migration`, `3.7` case `3.8-migration`, `3.8` + // Add 3.x-migration and 3.x here // !!! Keep in sync with scala.runtime.stdlibPatches.language !!! + case `2.13` case `future-migration`, `future` case `never` // needed for MigrationVersion.errorFrom if we never want to issue an error @@ -33,6 +36,8 @@ enum SourceVersion: def isAtMost(v: SourceVersion) = stable.ordinal <= v.ordinal + def isScala2 = this == `2.13` + def enablesFewerBraces = isAtLeast(`3.3`) def enablesClauseInterleaving = isAtLeast(`3.6`) def enablesNewGivens = isAtLeast(`3.6`) @@ -40,10 +45,18 @@ enum SourceVersion: def enablesBetterFors(using Context) = isAtLeast(`3.7`) && isPreviewEnabled object SourceVersion extends Property.Key[SourceVersion]: - def defaultSourceVersion = `3.7` + + /* The default source version used by the built compiler */ + val defaultSourceVersion = `3.7` + + /* Illegal source versions that may not appear in the settings `-source:<...>` */ + val illegalInSettings = List(`2.13`, `3.1-migration`, `never`) + + /* Illegal source versions that may not appear as an import `import scala.language.<...>` */ + val illegalInImports = List(`3.1-migration`, `never`) /** language versions that may appear in a language import, are deprecated, but not removed from the standard library. */ - val illegalSourceVersionNames = List("3.1-migration", "never").map(_.toTermName) + val illegalSourceVersionNames = illegalInImports.map(_.toString.toTermName) /** language versions that the compiler recognises. */ val validSourceVersionNames = values.toList.map(_.toString.toTermName) diff --git a/compiler/src/dotty/tools/dotc/core/Definitions.scala b/compiler/src/dotty/tools/dotc/core/Definitions.scala index 14f2491214e2..22632065674c 100644 --- a/compiler/src/dotty/tools/dotc/core/Definitions.scala +++ b/compiler/src/dotty/tools/dotc/core/Definitions.scala @@ -1537,9 +1537,7 @@ class Definitions { denot.sourceModule.info = denot.typeRef // we run into a cyclic reference when patching if this line is omitted patch2(denot, patchCls) - if ctx.settings.YcompileScala2Library.value then - () - else if denot.name == tpnme.Predef.moduleClassName && denot.symbol == ScalaPredefModuleClass then + if denot.name == tpnme.Predef.moduleClassName && denot.symbol == ScalaPredefModuleClass then patchWith(ScalaPredefModuleClassPatch) else if denot.name == tpnme.language.moduleClassName && denot.symbol == LanguageModuleClass then patchWith(LanguageModuleClassPatch) @@ -1880,7 +1878,7 @@ class Definitions { || tp.derivesFrom(defn.PolyFunctionClass) // TODO check for refinement? private def withSpecMethods(cls: ClassSymbol, bases: List[Name], paramTypes: Set[TypeRef]) = - if !ctx.settings.YcompileScala2Library.value then + if !Feature.shouldBehaveAsScala2 then for base <- bases; tp <- paramTypes do cls.enter(newSymbol(cls, base.specializedName(List(tp)), Method, ExprType(tp))) cls @@ -1923,7 +1921,7 @@ class Definitions { case List(x, y) => Tuple2SpecializedParamClasses().contains(x.classSymbol) && Tuple2SpecializedParamClasses().contains(y.classSymbol) case _ => false && base.owner.denot.info.member(base.name.specializedName(args)).exists // when dotc compiles the stdlib there are no specialised classes - && !ctx.settings.YcompileScala2Library.value // We do not add the specilized TupleN methods/classes when compiling the stdlib + && !Feature.shouldBehaveAsScala2 // We do not add the specilized TupleN methods/classes when compiling the stdlib def isSpecializableFunction(cls: ClassSymbol, paramTypes: List[Type], retType: Type)(using Context): Boolean = paramTypes.length <= 2 @@ -1945,7 +1943,7 @@ class Definitions { case _ => false }) - && !ctx.settings.YcompileScala2Library.value // We do not add the specilized FunctionN methods/classes when compiling the stdlib + && !Feature.shouldBehaveAsScala2 // We do not add the specilized FunctionN methods/classes when compiling the stdlib @tu lazy val Function0SpecializedApplyNames: List[TermName] = for r <- Function0SpecializedReturnTypes diff --git a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala index 41d3f5bbd676..0268ae2b2f58 100644 --- a/compiler/src/dotty/tools/dotc/inlines/Inliner.scala +++ b/compiler/src/dotty/tools/dotc/inlines/Inliner.scala @@ -165,28 +165,9 @@ object Inliner: else Nil case _ => Nil val refinements = openOpaqueAliases(cls.givenSelfType) - - // Map references in the refinements from the proxied termRef - // to the recursive type of the refined type - // e.g.: Obj.type{type A = Obj.B; type B = Int} -> Obj.type{type A = .B; type B = Int} - def mapRecTermRefReferences(recType: RecType, refinedType: Type) = - new TypeMap { - def apply(tp: Type) = tp match - case RefinedType(a: RefinedType, b, info) => RefinedType(apply(a), b, apply(info)) - case RefinedType(a, b, info) => RefinedType(a, b, apply(info)) - case TypeRef(prefix, des) => TypeRef(apply(prefix), des) - case termRef: TermRef if termRef == ref => recType.recThis - case _ => mapOver(tp) - }.apply(refinedType) - val refinedType = refinements.foldLeft(ref: Type): (parent, refinement) => RefinedType(parent, refinement._1, TypeAlias(refinement._2)) - - val recType = RecType.closeOver ( recType => - mapRecTermRefReferences(recType, refinedType) - ) - - val refiningSym = newSym(InlineBinderName.fresh(), Synthetic, recType, span) + val refiningSym = newSym(InlineBinderName.fresh(), Synthetic, refinedType, span) refiningSym.termRef def unapply(refiningRef: TermRef)(using Context): Option[TermRef] = @@ -405,9 +386,6 @@ class Inliner(val call: tpd.Tree)(using Context): */ private val opaqueProxies = new mutable.ListBuffer[(TermRef, TermRef)] - /** TermRefs for which we already started synthesising proxies */ - private val visitedTermRefs = new mutable.HashSet[TermRef] - protected def hasOpaqueProxies = opaqueProxies.nonEmpty /** Map first halves of opaqueProxies pairs to second halves, using =:= as equality */ @@ -435,15 +413,12 @@ class Inliner(val call: tpd.Tree)(using Context): for cls <- ref.widen.baseClasses do if cls.containsOpaques && (forThisProxy || inlinedMethod.isContainedIn(cls)) - && !visitedTermRefs.contains(ref) + && mapRef(ref).isEmpty then - visitedTermRefs += ref val refiningRef = OpaqueProxy(ref, cls, call.span) val refiningSym = refiningRef.symbol.asTerm val refinedType = refiningRef.info - val refiningDef = addProxiesForRecurrentOpaques( - ValDef(refiningSym, tpd.ref(ref).cast(refinedType), inferred = true).withSpan(span) - ) + val refiningDef = ValDef(refiningSym, tpd.ref(ref).cast(refinedType), inferred = true).withSpan(span) inlining.println(i"add opaque alias proxy $refiningDef for $ref in $tp") bindingsBuf += refiningDef opaqueProxies += ((ref, refiningSym.termRef)) @@ -463,27 +438,6 @@ class Inliner(val call: tpd.Tree)(using Context): } ) - /** Transforms proxies that reference other opaque types, like for: - * object Obj1 { opaque type A = Int } - * object Obj2 { opaque type B = A } - * and proxy$1 of type Obj2.type{type B = Obj1.A} - * creates proxy$2 of type Obj1.type{type A = Int} - * and transforms proxy$1 into Obj2.type{type B = proxy$2.A} - */ - private def addProxiesForRecurrentOpaques(binding: ValDef)(using Context): ValDef = - def fixRefinedTypes(ref: Type): Unit = - ref match - case recType: RecType => fixRefinedTypes(recType.underlying) - case RefinedType(parent, name, info) => - addOpaqueProxies(info.widen, binding.span, true) - fixRefinedTypes(parent) - case _ => - fixRefinedTypes(binding.symbol.info) - binding.symbol.info = mapOpaques.typeMap(binding.symbol.info) - mapOpaques.transform(binding).asInstanceOf[ValDef] - .showing(i"transformed this binding exposing opaque aliases: $result", inlining) - end addProxiesForRecurrentOpaques - /** If `binding` contains TermRefs that refer to objects with opaque * type aliases, add proxy definitions that expose these aliases * and substitute such TermRefs with theproxies. Example from pos/opaque-inline1.scala: diff --git a/compiler/src/dotty/tools/dotc/reporting/messages.scala b/compiler/src/dotty/tools/dotc/reporting/messages.scala index ab9fc507b052..d4b7e2901568 100644 --- a/compiler/src/dotty/tools/dotc/reporting/messages.scala +++ b/compiler/src/dotty/tools/dotc/reporting/messages.scala @@ -3310,23 +3310,29 @@ extends TypeMsg(ConstructorProxyNotValueID): |are not values themselves, they can only be referred to in selections.""" class UnusedSymbol(errorText: String, val actions: List[CodeAction] = Nil)(using Context) -extends Message(UnusedSymbolID) { +extends Message(UnusedSymbolID): def kind = MessageKind.UnusedSymbol override def msg(using Context) = errorText override def explain(using Context) = "" override def actions(using Context) = this.actions -} object UnusedSymbol: def imports(actions: List[CodeAction])(using Context): UnusedSymbol = UnusedSymbol(i"unused import", actions) def localDefs(using Context): UnusedSymbol = UnusedSymbol(i"unused local definition") - def explicitParams(using Context): UnusedSymbol = UnusedSymbol(i"unused explicit parameter") - def implicitParams(using Context): UnusedSymbol = UnusedSymbol(i"unused implicit parameter") + def explicitParams(sym: Symbol)(using Context): UnusedSymbol = + UnusedSymbol(i"unused explicit parameter${paramAddendum(sym)}") + def implicitParams(sym: Symbol)(using Context): UnusedSymbol = + UnusedSymbol(i"unused implicit parameter${paramAddendum(sym)}") def privateMembers(using Context): UnusedSymbol = UnusedSymbol(i"unused private member") def patVars(using Context): UnusedSymbol = UnusedSymbol(i"unused pattern variable") - def unsetLocals(using Context): UnusedSymbol = UnusedSymbol(i"unset local variable, consider using an immutable val instead") - def unsetPrivates(using Context): UnusedSymbol = UnusedSymbol(i"unset private variable, consider using an immutable val instead") + def unsetLocals(using Context): UnusedSymbol = + UnusedSymbol(i"unset local variable, consider using an immutable val instead") + def unsetPrivates(using Context): UnusedSymbol = + UnusedSymbol(i"unset private variable, consider using an immutable val instead") + private def paramAddendum(sym: Symbol)(using Context): String = + if sym.denot.owner.is(ExtensionMethod) then i" in extension ${sym.denot.owner}" + else "" class NonNamedArgumentInJavaAnnotation(using Context) extends SyntaxMsg(NonNamedArgumentInJavaAnnotationID): diff --git a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala index fafb8ea72c1c..6b5dd96f0493 100644 --- a/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala +++ b/compiler/src/dotty/tools/dotc/transform/CheckUnused.scala @@ -215,15 +215,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha refInfos.register(tree) tree - override def prepareForTemplate(tree: Template)(using Context): Context = - ctx.fresh.setProperty(resolvedKey, Resolved()) - - override def prepareForPackageDef(tree: PackageDef)(using Context): Context = - ctx.fresh.setProperty(resolvedKey, Resolved()) - - override def prepareForStats(trees: List[Tree])(using Context): Context = - ctx.fresh.setProperty(resolvedKey, Resolved()) - override def transformOther(tree: Tree)(using Context): tree.type = tree match case imp: Import => @@ -289,7 +280,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha case ByNameTypeTree(result) => transformAllDeep(result) //case _: InferredTypeTree => // do nothing - //case _: Export => // nothing to do //case _ if tree.isType => case _ => tree @@ -350,15 +340,6 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha && ctxsym.thisType.baseClasses.contains(sym.owner) && ctxsym.thisType.member(sym.name).hasAltWith(d => d.containsSym(sym) && !name.exists(_ != d.name)) - // Attempt to cache a result at the given context. Not all contexts bear a cache, including NoContext. - // If there is already any result for the name and prefix, do nothing. - def addCached(where: Context, result: Precedence): Unit = - if where.moreProperties ne null then - where.property(resolvedKey) match - case Some(resolved) => - resolved.record(sym, name, prefix, result) - case none => - // Avoid spurious NoSymbol and also primary ctors which are never warned about. // Selections C.this.toString should be already excluded, but backtopped here for eq, etc. if !sym.exists || sym.isPrimaryConstructor || sym.isEffectiveRoot || defn.topClasses(sym.owner) then return @@ -367,39 +348,20 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha // If the sym is an enclosing definition (the owner of a context), it does not count toward usages. val isLocal = sym.isLocalToBlock var candidate: Context = NoContext - var cachePoint: Context = NoContext // last context with Resolved cache var importer: ImportSelector | Null = null // non-null for import context var precedence = NoPrecedence // of current resolution + var enclosed = false // true if sym is owner of an enclosing context var done = false - var cached = false val ctxs = ctx.outersIterator while !done && ctxs.hasNext do val cur = ctxs.next() - if cur.owner eq sym then - addCached(cachePoint, Definition) - return // found enclosing definition - else if isLocal then + if cur.owner.userSymbol == sym && !sym.is(Package) then + enclosed = true // found enclosing definition, don't register the reference + if isLocal then if cur.owner eq sym.owner then done = true // for local def, just checking that it is not enclosing else - val cachedPrecedence = - cur.property(resolvedKey) match - case Some(resolved) => - // conservative, cache must be nested below the result context - if precedence.isNone then - cachePoint = cur // no result yet, and future result could be cached here - resolved.hasRecord(sym, name, prefix) - case none => NoPrecedence - cached = !cachedPrecedence.isNone - if cached then - // if prefer cached precedence, then discard previous result - if precedence.weakerThan(cachedPrecedence) then - candidate = NoContext - importer = null - cachePoint = cur // actual cache context - precedence = cachedPrecedence // actual cached precedence - done = true - else if cur.isImportContext then + if cur.isImportContext then val sel = matchingSelector(cur.importInfo.nn) if sel != null then if cur.importInfo.nn.isRootImport then @@ -419,7 +381,7 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha candidate = cur importer = sel else if checkMember(cur.owner) then - if sym.srcPos.sourcePos.source == ctx.source then + if sym.is(Package) || sym.srcPos.sourcePos.source == ctx.source then precedence = Definition candidate = cur importer = null // ignore import in same scope; we can't check nesting level @@ -429,16 +391,10 @@ class CheckUnused private (phaseMode: PhaseMode, suffix: String) extends MiniPha candidate = cur end while // record usage and possibly an import - refInfos.refs.addOne(sym) + if !enclosed then + refInfos.refs.addOne(sym) if candidate != NoContext && candidate.isImportContext && importer != null then refInfos.sels.put(importer, ()) - // possibly record that we have performed this look-up - // if no result was found, take it as Definition (local or rooted head of fully qualified path) - val adjusted = if precedence.isNone then Definition else precedence - if !cached && (cachePoint ne NoContext) then - addCached(cachePoint, adjusted) - if cachePoint ne ctx then - addCached(ctx, adjusted) // at this ctx, since cachePoint may be far up the outer chain end resolveUsage end CheckUnused @@ -450,15 +406,8 @@ object CheckUnused: val refInfosKey = Property.StickyKey[RefInfos] - val resolvedKey = Property.Key[Resolved] - inline def refInfos(using Context): RefInfos = ctx.property(refInfosKey).get - inline def resolved(using Context): Resolved = - ctx.property(resolvedKey) match - case Some(res) => res - case _ => throw new MatchError("no Resolved for context") - /** Attachment holding the name of an Ident as written by the user. */ val OriginalName = Property.StickyKey[Name] @@ -487,7 +436,7 @@ object CheckUnused: if inliners == 0 && languageImport(imp.expr).isEmpty && !imp.isGeneratedByEnum - && !ctx.outer.owner.name.isReplWrapperName + && !ctx.owner.name.isReplWrapperName then imps.put(imp, ()) case tree: Bind => @@ -514,24 +463,6 @@ object CheckUnused: var inliners = 0 // depth of inline def (not inlined yet) end RefInfos - // Symbols already resolved in the given Context (with name and prefix of lookup). - class Resolved: - import PrecedenceLevels.* - private val seen = mutable.Map.empty[Symbol, List[(Name, Type, Precedence)]].withDefaultValue(Nil) - // if a result has been recorded, return it; otherwise, NoPrecedence. - def hasRecord(symbol: Symbol, name: Name, prefix: Type)(using Context): Precedence = - seen(symbol).find((n, p, _) => n == name && p =:= prefix) match - case Some((_, _, r)) => r - case none => NoPrecedence - // "record" the look-up result, if there is not already a result for the name and prefix. - def record(symbol: Symbol, name: Name, prefix: Type, result: Precedence)(using Context): Unit = - require(NoPrecedence.weakerThan(result)) - seen.updateWith(symbol): - case svs @ Some(vs) => - if vs.exists((n, p, _) => n == name && p =:= prefix) then svs - else Some((name, prefix, result) :: vs) - case none => Some((name, prefix, result) :: Nil) - // Names are resolved by definitions and imports, which have four precedence levels: object PrecedenceLevels: opaque type Precedence = Int @@ -557,6 +488,8 @@ object CheckUnused: val warnings = ArrayBuilder.make[MessageInfo] def warnAt(pos: SrcPos)(msg: UnusedSymbol, origin: String = ""): Unit = warnings.addOne((msg, pos, origin)) val infos = refInfos + //println(infos.defs.mkString("DEFS\n", "\n", "\n---")) + //println(infos.refs.mkString("REFS\n", "\n", "\n---")) def checkUnassigned(sym: Symbol, pos: SrcPos) = if sym.isLocalToBlock then @@ -597,7 +530,7 @@ object CheckUnused: if aliasSym.isAllOf(PrivateParamAccessor, butNot = CaseAccessor) && !infos.refs(alias.symbol) then if aliasSym.is(Local) then if ctx.settings.WunusedHas.explicits then - warnAt(pos)(UnusedSymbol.explicitParams) + warnAt(pos)(UnusedSymbol.explicitParams(aliasSym)) else if ctx.settings.WunusedHas.privates then warnAt(pos)(UnusedSymbol.privateMembers) @@ -611,7 +544,7 @@ object CheckUnused: && !sym.name.isInstanceOf[DerivedName] && !ctx.platform.isMainMethod(m) then - warnAt(pos)(UnusedSymbol.explicitParams) + warnAt(pos)(UnusedSymbol.explicitParams(sym)) end checkExplicit // begin if !infos.skip(m) @@ -651,9 +584,9 @@ object CheckUnused: aliasSym.isAllOf(PrivateParamAccessor, butNot = CaseAccessor) || aliasSym.isAllOf(Protected | ParamAccessor, butNot = CaseAccessor) && m.owner.is(Given) if checking && !infos.refs(alias.symbol) then - warnAt(pos)(UnusedSymbol.implicitParams) + warnAt(pos)(UnusedSymbol.implicitParams(aliasSym)) else - warnAt(pos)(UnusedSymbol.implicitParams) + warnAt(pos)(UnusedSymbol.implicitParams(sym)) def checkLocal(sym: Symbol, pos: SrcPos) = if ctx.settings.WunusedHas.locals diff --git a/compiler/src/dotty/tools/dotc/transform/Pickler.scala b/compiler/src/dotty/tools/dotc/transform/Pickler.scala index fcf1b384fda1..85c06f3e9948 100644 --- a/compiler/src/dotty/tools/dotc/transform/Pickler.scala +++ b/compiler/src/dotty/tools/dotc/transform/Pickler.scala @@ -291,7 +291,7 @@ class Pickler extends Phase { val isOutline = isJavaAttr // TODO: later we may want outline for Scala sources too val attributes = Attributes( sourceFile = sourceRelativePath, - scala2StandardLibrary = ctx.settings.YcompileScala2Library.value, + scala2StandardLibrary = Feature.shouldBehaveAsScala2, explicitNulls = ctx.settings.YexplicitNulls.value, captureChecked = Feature.ccEnabled, withPureFuns = Feature.pureFunsEnabled, diff --git a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala index a7d1e70ea90e..6480ae7fdd05 100644 --- a/compiler/src/dotty/tools/dotc/transform/PostTyper.scala +++ b/compiler/src/dotty/tools/dotc/transform/PostTyper.scala @@ -101,7 +101,7 @@ class PostTyper extends MacroTransform with InfoTransformer { thisPhase => private var compilingScala2StdLib = false override def initContext(ctx: FreshContext): Unit = initContextCalled = true - compilingScala2StdLib = ctx.settings.YcompileScala2Library.value(using ctx) + compilingScala2StdLib = Feature.shouldBehaveAsScala2(using ctx) val superAcc: SuperAccessors = new SuperAccessors(thisPhase) val synthMbr: SyntheticMembers = new SyntheticMembers(thisPhase) diff --git a/compiler/src/dotty/tools/dotc/transform/SpecializeApplyMethods.scala b/compiler/src/dotty/tools/dotc/transform/SpecializeApplyMethods.scala index fd314b94e50c..c85f06e6075f 100644 --- a/compiler/src/dotty/tools/dotc/transform/SpecializeApplyMethods.scala +++ b/compiler/src/dotty/tools/dotc/transform/SpecializeApplyMethods.scala @@ -5,6 +5,7 @@ import ast.Trees.*, ast.tpd, core.* import Contexts.*, Types.*, Decorators.*, Symbols.*, DenotTransformers.* import SymDenotations.*, Scopes.*, StdNames.*, NameOps.*, Names.* import MegaPhase.MiniPhase +import config.Feature import scala.collection.mutable @@ -25,7 +26,7 @@ class SpecializeApplyMethods extends MiniPhase with InfoTransformer { override def description: String = SpecializeApplyMethods.description override def isEnabled(using Context): Boolean = - !ctx.settings.scalajs.value && !ctx.settings.YcompileScala2Library.value + !ctx.settings.scalajs.value && !Feature.shouldBehaveAsScala2 private def specApplySymbol(sym: Symbol, args: List[Type], ret: Type)(using Context): Symbol = { val name = nme.apply.specializedFunction(ret, args) diff --git a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala index 4bc9575996d1..5f1039abec7b 100644 --- a/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala +++ b/compiler/src/dotty/tools/dotc/transform/SyntheticMembers.scala @@ -10,6 +10,7 @@ import NameOps.* import Annotations.Annotation import typer.ProtoTypes.constrained import ast.untpd +import config.Feature import util.Property import util.Spans.Span @@ -79,7 +80,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { private def existingDef(sym: Symbol, clazz: ClassSymbol)(using Context): Symbol = val existing = sym.matchingMember(clazz.thisType) - if ctx.settings.YcompileScala2Library.value && clazz.isValueClass && (sym == defn.Any_equals || sym == defn.Any_hashCode) then + if Feature.shouldBehaveAsScala2 && clazz.isValueClass && (sym == defn.Any_equals || sym == defn.Any_hashCode) then NoSymbol else if existing != sym && !existing.is(Deferred) then existing @@ -168,7 +169,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { case nme.productPrefix if isEnumValue => nameRef case nme.productPrefix => ownNameLit case nme.productElement => - if ctx.settings.YcompileScala2Library.value then productElementBodyForScala2Compat(accessors.length, vrefss.head.head) + if Feature.shouldBehaveAsScala2 then productElementBodyForScala2Compat(accessors.length, vrefss.head.head) else productElementBody(accessors.length, vrefss.head.head) case nme.productElementName => productElementNameBody(accessors.length, vrefss.head.head) } @@ -720,7 +721,7 @@ class SyntheticMembers(thisPhase: DenotTransformer) { val syntheticMembers = serializableObjectMethod(clazz) ::: serializableEnumValueMethod(clazz) ::: caseAndValueMethods(clazz) checkInlining(syntheticMembers) val impl1 = cpy.Template(impl)(body = syntheticMembers ::: impl.body) - if ctx.settings.YcompileScala2Library.value then impl1 + if Feature.shouldBehaveAsScala2 then impl1 else addMirrorSupport(impl1) } diff --git a/compiler/src/dotty/tools/dotc/typer/Applications.scala b/compiler/src/dotty/tools/dotc/typer/Applications.scala index 54f033fe6fd8..2505aff0bd33 100644 --- a/compiler/src/dotty/tools/dotc/typer/Applications.scala +++ b/compiler/src/dotty/tools/dotc/typer/Applications.scala @@ -2140,27 +2140,16 @@ trait Applications extends Compatibility { def resolveOverloaded(alts: List[TermRef], pt: Type)(using Context): List[TermRef] = record("resolveOverloaded") - /** Is `alt` a method or polytype whose approximated result type after the first value parameter + /** Is `alt` a method or polytype whose result type after the first value parameter * section conforms to the expected type `resultType`? If `resultType` * is a `IgnoredProto`, pick the underlying type instead. - * - * Using an approximated result type is necessary to avoid false negatives - * due to incomplete type inference such as in tests/pos/i21410.scala and tests/pos/i21410b.scala. */ def resultConforms(altSym: Symbol, altType: Type, resultType: Type)(using Context): Boolean = resultType.revealIgnored match { case resultType: ValueType => altType.widen match { case tp: PolyType => resultConforms(altSym, instantiateWithTypeVars(tp), resultType) - case tp: MethodType => - val wildRes = wildApprox(tp.resultType) - - class ResultApprox extends AvoidWildcardsMap: - // Avoid false negatives by approximating to a lower bound - variance = -1 - - val approx = ResultApprox()(wildRes) - constrainResult(altSym, approx, resultType) + case tp: MethodType => constrainResult(altSym, tp.resultType, resultType) case _ => true } case _ => true @@ -2532,7 +2521,6 @@ trait Applications extends Compatibility { if t.exists && alt.symbol.exists then val (trimmed, skipped) = trimParamss(t.stripPoly, alt.symbol.rawParamss) val mappedSym = alt.symbol.asTerm.copy(info = t) - mappedSym.annotations = alt.symbol.annotations mappedSym.rawParamss = trimmed val (pre, totalSkipped) = mappedAltInfo(alt.symbol) match case Some((pre, prevSkipped)) => diff --git a/compiler/src/dotty/tools/dotc/typer/Namer.scala b/compiler/src/dotty/tools/dotc/typer/Namer.scala index 5d6be936f11b..3c9273cdfa2e 100644 --- a/compiler/src/dotty/tools/dotc/typer/Namer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Namer.scala @@ -247,7 +247,7 @@ class Namer { typer: Typer => tree match { case tree: TypeDef if tree.isClassDef => var flags = checkFlags(tree.mods.flags) - if ctx.settings.YcompileScala2Library.value then + if Feature.shouldBehaveAsScala2 then flags |= Scala2x val name = checkNoConflict(tree.name, tree.span).asTypeName val cls = diff --git a/compiler/src/dotty/tools/dotc/typer/Typer.scala b/compiler/src/dotty/tools/dotc/typer/Typer.scala index 79aaf367851a..21a2acc69ac1 100644 --- a/compiler/src/dotty/tools/dotc/typer/Typer.scala +++ b/compiler/src/dotty/tools/dotc/typer/Typer.scala @@ -3206,7 +3206,7 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer checkEnumParent(cls, firstParent) - if defn.ScalaValueClasses()(cls) && ctx.settings.YcompileScala2Library.value then + if defn.ScalaValueClasses()(cls) && Feature.shouldBehaveAsScala2 then constr1.symbol.resetFlag(Private) val self1 = typed(self)(using ctx.outer).asInstanceOf[ValDef] // outer context where class members are not visible diff --git a/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala b/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala index 07834684d33b..c74be4901137 100644 --- a/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala +++ b/compiler/test/dotty/tools/dotc/config/ScalaSettingsTests.scala @@ -299,4 +299,11 @@ class ScalaSettingsTests: ) assertEquals(result, Right(reporting.Action.Error)) + @Test def `illegal source versions are not accepted when parsing the settings`: Unit = + for source <- SourceVersion.illegalInSettings do + val settings = ScalaSettings + val result = settings.processArguments(List("-source", source.toString()), true) + assertEquals(0, result.warnings.length) + assertEquals(1, result.errors.length) + end ScalaSettingsTests diff --git a/library/src/scala/runtime/stdLibPatches/language.scala b/library/src/scala/runtime/stdLibPatches/language.scala index 8899f734aece..0f5e904e29bb 100644 --- a/library/src/scala/runtime/stdLibPatches/language.scala +++ b/library/src/scala/runtime/stdLibPatches/language.scala @@ -222,6 +222,12 @@ object language: @compileTimeOnly("`future-migration` can only be used at compile time in import statements") object `future-migration` + /** Set source version to 2.13. Effectively, this doesn't change the source language, + * but rather adapts the generated code as if it was compiled with Scala 2.13 + */ + @compileTimeOnly("`2.13` can only be used at compile time in import statements") + private[scala] object `2.13` + /** Set source version to 3.0-migration. * * @see [[https://docs.scala-lang.org/scala3/guides/migration/compatibility-intro.html]] diff --git a/project/Build.scala b/project/Build.scala index 3ea865fb00db..70bc45f27c11 100644 --- a/project/Build.scala +++ b/project/Build.scala @@ -103,7 +103,7 @@ object Build { * * Warning: Change of this variable needs to be consulted with `expectedTastyVersion` */ - val referenceVersion = "3.7.0-RC4" + val referenceVersion = "3.7.0" /** Version of the Scala compiler targeted in the current release cycle * Contains a version without RC/SNAPSHOT/NIGHTLY specific suffixes @@ -123,7 +123,7 @@ object Build { * During release candidate cycle incremented by the release officer before publishing a subsequent RC version; * During final, stable release is set exactly to `developedVersion`. */ - val baseVersion = s"$developedVersion-RC1" + val baseVersion = s"$developedVersion-RC2" /** The version of TASTY that should be emitted, checked in runtime test * For defails on how TASTY version should be set see related discussions: @@ -141,7 +141,7 @@ object Build { * - in release candidate branch is experimental if {patch == 0} * - in stable release is always non-experimetnal */ - val expectedTastyVersion = "28.7-experimental-1" + val expectedTastyVersion = "28.7" checkReleasedTastyVersion() /** Final version of Scala compiler, controlled by environment variables. */ @@ -178,7 +178,7 @@ object Build { * - `3.(M-1).0` if `P = 0` * 3.6.2 is an exception from this rule - 3.6.0 was a broken release, 3.6.1 was hotfix (unstable) release */ - val mimaPreviousDottyVersion = "3.7.0-RC1" + val mimaPreviousDottyVersion = "3.7.0" /** LTS version against which we check binary compatibility. * @@ -189,7 +189,7 @@ object Build { val mimaPreviousLTSDottyVersion = "3.3.0" /** Version of Scala CLI to download */ - val scalaCliLauncherVersion = "1.7.1" + val scalaCliLauncherVersion = "1.8.0" /** Version of Coursier to download for initializing the local maven repo of Scala command */ val coursierJarVersion = "2.1.24" @@ -1237,10 +1237,7 @@ object Build { withCommonSettings(Bootstrapped). dependsOn(dottyCompiler(Bootstrapped) % "provided; compile->runtime; test->test"). settings(scala2LibraryBootstrappedSettings). - settings( - moduleName := "scala2-library-cc", - scalacOptions += "-Ycheck:all", - ) + settings(moduleName := "scala2-library-cc") lazy val scala2LibraryBootstrappedSettings = Seq( javaOptions := (`scala3-compiler-bootstrapped` / javaOptions).value, diff --git a/project/MiMaFilters.scala b/project/MiMaFilters.scala index a7f857e8a719..59052036e2ab 100644 --- a/project/MiMaFilters.scala +++ b/project/MiMaFilters.scala @@ -13,6 +13,9 @@ object MiMaFilters { // Scala.js-only class ProblemFilters.exclude[FinalClassProblem]("scala.scalajs.runtime.AnonFunctionXXL"), ProblemFilters.exclude[DirectMissingMethodProblem]("scala.scalajs.runtime.AnonFunctionXXL.this"), + + ProblemFilters.exclude[MissingFieldProblem]("scala.runtime.stdLibPatches.language.2.13"), + ProblemFilters.exclude[MissingClassProblem]("scala.runtime.stdLibPatches.language$2$u002E13$") ), // Additions since last LTS diff --git a/project/scripts/scala2-library-tasty-mima.sh b/project/scripts/scala2-library-tasty-mima.sh index 7118ee28c2f3..ddb3a6e09e69 100755 --- a/project/scripts/scala2-library-tasty-mima.sh +++ b/project/scripts/scala2-library-tasty-mima.sh @@ -18,6 +18,6 @@ setTastyVersion $MINOR_TASTY_VERSION_SUPPORTED_BY_TASTY_MIMA 0 # We clean before to make sure all sources are recompiled using the new TASTY version. # We clean after to make sure no other test will use the TASTy generated with this version. # We set -Ycheck:all to check that -Ycompile-scala2-library does not gererate inconsistent trees. -"$SBT" 'clean; scala2-library-bootstrapped/clean; reload; set `scala2-library-bootstrapped`/scalacOptions += "-Ycheck:all"; scala2-library-bootstrapped/tastyMiMaReportIssues; clean; scala2-library-bootstrapped/clean' +"$SBT" 'clean; scala2-library-bootstrapped/clean; reload; scala2-library-bootstrapped/tastyMiMaReportIssues; clean; scala2-library-bootstrapped/clean' setTastyVersion $MINOR_TASTY_VERSION $EXPERIMENTAL_TASTY_VERSION diff --git a/tasty/src/dotty/tools/tasty/TastyFormat.scala b/tasty/src/dotty/tools/tasty/TastyFormat.scala index de3700c667a4..4c1453243450 100644 --- a/tasty/src/dotty/tools/tasty/TastyFormat.scala +++ b/tasty/src/dotty/tools/tasty/TastyFormat.scala @@ -340,7 +340,7 @@ object TastyFormat { * is able to read final TASTy documents if the file's * `MinorVersion` is strictly less than the current value. */ - final val ExperimentalVersion: Int = 1 + final val ExperimentalVersion: Int = 0 /**This method implements a binary relation (`<:<`) between two TASTy versions. * diff --git a/tests/pos/22359a.scala b/tests/pos/22359a.scala deleted file mode 100644 index a3b9ef63257a..000000000000 --- a/tests/pos/22359a.scala +++ /dev/null @@ -1,15 +0,0 @@ -opaque type NT[N <: Tuple, V <: Tuple] = V -opaque type System = NT[Tuple1["wires"], Tuple1[Any]] - -extension [N <: Tuple, V <: Tuple] (x: NT[N, V]) { - inline def apply(n: Int): Any = - x.productElement(n) -} - -extension (system: System) { - inline def foo = - system.apply(0) -} - -val simulation: System = ??? -val _ = simulation.foo diff --git a/tests/pos/22359b.scala b/tests/pos/22359b.scala deleted file mode 100644 index f6b7cbb462c1..000000000000 --- a/tests/pos/22359b.scala +++ /dev/null @@ -1,17 +0,0 @@ -object Obj2: - opaque type NT[N <: Tuple, V <: Tuple] = V - - extension [N <: Tuple, V <: Tuple] (x: NT[N, V]) { - inline def apply(n: Int): Any = - x.productElement(n) - } - -object Obj: - opaque type System = Obj2.NT[Tuple1["wires"], Tuple1[Any]] - - extension (system: System) { - inline def foo = system.apply(0) - } -import Obj._ -val simulation: System = ??? -val _ = simulation.foo diff --git a/tests/pos/i17243.scala b/tests/pos/i17243.scala deleted file mode 100644 index 3d42495b26b0..000000000000 --- a/tests/pos/i17243.scala +++ /dev/null @@ -1,17 +0,0 @@ -object Opaque: - opaque type A = Int - - val va: A = 1 - - inline def a(x: A) = - x + 1 - -object Opaque2: - opaque type B = Opaque.A - - val vb: B = Opaque.va - - inline def b(x: B) = Opaque.a(x) - -@main def Test() = - print(Opaque2.b(Opaque2.vb)) diff --git a/tests/pos/i21410.scala b/tests/pos/i21410.scala deleted file mode 100644 index c3ba3ea862bc..000000000000 --- a/tests/pos/i21410.scala +++ /dev/null @@ -1,12 +0,0 @@ -class A -object Test: - type F[X] <: Any = X match - case A => Int - - def foo[T](x: String): T = ??? - def foo[U](x: U): F[U] = ??? - - val x1 = foo(A()) - val y: Int = x1 - - val x2: Int = foo(A()) // error diff --git a/tests/pos/i21410b.scala b/tests/pos/i21410b.scala deleted file mode 100644 index a17ad59bc59e..000000000000 --- a/tests/pos/i21410b.scala +++ /dev/null @@ -1,10 +0,0 @@ -object Test: - def foo[T](x: Option[T]): T = ??? - def foo[T <: Tuple](x: T): Tuple.Map[T, List] = ??? - - val tup: (Int, String) = (1, "") - - val x = foo(tup) - val y: (List[Int], List[String]) = x - - val x2: (List[Int], List[String]) = foo(tup) // error diff --git a/tests/pos/i21410c.scala b/tests/pos/i21410c.scala deleted file mode 100644 index 21f69fec20fa..000000000000 --- a/tests/pos/i21410c.scala +++ /dev/null @@ -1,11 +0,0 @@ -class AppliedPIso[A, B]() -case class User(age: Int) - -object Test: - extension [From, To](from: From) - def focus(): AppliedPIso[From, From] = ??? - transparent inline def focus(inline lambda: (From => To)): Any = ??? - - - val u = User(1) - val ap: AppliedPIso[User, User] = u.focus(_.age) // error diff --git a/tests/pos/i22974a/Maybe_1.scala b/tests/pos/i22974a/Maybe_1.scala new file mode 100644 index 000000000000..bd4964b29582 --- /dev/null +++ b/tests/pos/i22974a/Maybe_1.scala @@ -0,0 +1,14 @@ +package pack +import Maybe._ +opaque type Maybe[+A] >: (Absent | Present[A]) = Absent | Present[A] +object Maybe: + sealed abstract class Absent + case object Absent extends Absent + object internal: + case class PresentAbsent(val depth: Int) + opaque type Present[+A] = A | internal.PresentAbsent + + extension [A](self: Maybe[A]) { + inline def flatten[B]: Maybe[B] = ??? + inline def isDefined: Boolean = ??? + } diff --git a/tests/pos/i22974a/macro_1.scala b/tests/pos/i22974a/macro_1.scala new file mode 100644 index 000000000000..61d7783bd38a --- /dev/null +++ b/tests/pos/i22974a/macro_1.scala @@ -0,0 +1,6 @@ +import scala.quoted._ + +inline def passThorugh(inline condition: Boolean): Any = + ${ passThorughImpl('{condition}) } + +def passThorughImpl(condition: Expr[Boolean])(using Quotes): Expr[Any] = condition diff --git a/tests/pos/i22974a/main_2.scala b/tests/pos/i22974a/main_2.scala new file mode 100644 index 000000000000..a0b55aff7f52 --- /dev/null +++ b/tests/pos/i22974a/main_2.scala @@ -0,0 +1,6 @@ +object Test { + def main(): Unit = + import pack.Maybe + val res: Maybe[Maybe[Int]] = ??? + passThorugh(res.flatten.isDefined) +} diff --git a/tests/pos/i22974b.scala b/tests/pos/i22974b.scala new file mode 100644 index 000000000000..4f6e23c0f97d --- /dev/null +++ b/tests/pos/i22974b.scala @@ -0,0 +1,18 @@ +object outer: + opaque type Queue = Queue.Unsafe + object Queue: + abstract class Unsafe + opaque type Unbounded = Queue + object Unbounded: + inline def initWith()(f: Unbounded => Unit): Unit = + f(Unsafe.init()) + + opaque type Unsafe <: Queue.Unsafe = Queue + object Unsafe: + def init[A](): Unsafe = ??? + +object Resource: + def run: Unit = + outer.Queue.Unbounded.initWith() { q => + ??? + } diff --git a/tests/pos/i22974c.scala b/tests/pos/i22974c.scala new file mode 100644 index 000000000000..77833340de19 --- /dev/null +++ b/tests/pos/i22974c.scala @@ -0,0 +1,18 @@ +object other: + sealed abstract class Absent + case object Absent extends Absent + case class PresentAbsent(val depth: Int) + opaque type Present[+A] = A | PresentAbsent + opaque type Maybe[+A] >: (Absent | Present[A]) = Absent | Present[A] + + extension [A](self: Maybe[A]) { + inline def flatten[B]: Maybe[B] = if self.isEmpty then Absent else ??? + def isEmpty: Boolean = self.isInstanceOf[Absent] + } + +class Test { + def main(): Unit = + import other.Maybe + val res: Maybe[Maybe[Int]] = ??? + res.flatten +} diff --git a/tests/warn/i15503g.check b/tests/warn/i15503g.check new file mode 100644 index 000000000000..105df82e8a1a --- /dev/null +++ b/tests/warn/i15503g.check @@ -0,0 +1,28 @@ +-- [E198] Unused Symbol Warning: tests/warn/i15503g.scala:8:17 --------------------------------------------------------- +8 | private def f2(a: Int) = default_int // warn + | ^ + | unused explicit parameter +-- [E198] Unused Symbol Warning: tests/warn/i15503g.scala:9:31 --------------------------------------------------------- +9 | private def f3(a: Int)(using Int) = a // warn + | ^ + | unused implicit parameter +-- [E198] Unused Symbol Warning: tests/warn/i15503g.scala:10:17 -------------------------------------------------------- +10 | private def f4(a: Int)(using Int) = default_int // warn // warn + | ^ + | unused explicit parameter +-- [E198] Unused Symbol Warning: tests/warn/i15503g.scala:10:31 -------------------------------------------------------- +10 | private def f4(a: Int)(using Int) = default_int // warn // warn + | ^ + | unused implicit parameter +-- [E198] Unused Symbol Warning: tests/warn/i15503g.scala:11:17 -------------------------------------------------------- +11 | private def f6(a: Int)(using Int) = summon[Int] // warn + | ^ + | unused explicit parameter +-- [E198] Unused Symbol Warning: tests/warn/i15503g.scala:23:18 -------------------------------------------------------- +23 | def isAnIssue(y: A): Boolean = x == x // warn + | ^ + | unused explicit parameter in extension method isAnIssue +-- [E198] Unused Symbol Warning: tests/warn/i15503g.scala:29:30 -------------------------------------------------------- +29 | extension (s: String)(using Show) // warn not used in repeat + | ^ + | unused implicit parameter in extension method repeat diff --git a/tests/warn/i15503g.scala b/tests/warn/i15503g.scala index cfbfcdb04d1e..f63f7ea73475 100644 --- a/tests/warn/i15503g.scala +++ b/tests/warn/i15503g.scala @@ -1,4 +1,4 @@ -//> using options -Wunused:params +//> using options -Wunused:params /* This goes around the "trivial method" detection */ object Foo { @@ -15,10 +15,17 @@ object Foo { private def g2(x: Int) = ??? // OK } -package foo.test.i17101: +object i17101: type Test[A] = A extension[A] (x: Test[A]) { // OK def value: A = x def causesIssue: Unit = println("oh no") def isAnIssue(y: A): Boolean = x == x // warn } + +object i23125: + trait Show: + def show(s: String) = s + extension (s: String)(using Show) // warn not used in repeat + def echo = println(summon[Show].show(s)) + def repeat = s * 2 diff --git a/tests/warn/i22971.scala b/tests/warn/i22971.scala new file mode 100644 index 000000000000..63eee06a8c52 --- /dev/null +++ b/tests/warn/i22971.scala @@ -0,0 +1,34 @@ +//> using options -Wunused:imports + +package p: + + trait Base + class Class extends Base + + abstract class Entity[T: GetType] + + class Thing extends Entity[Class] + + trait GetType[T] + + object GetType { + //implicit object GetTypeClass extends GetType[Class] + implicit val GetTypeClass: GetType[Class] = new GetType[Class] {} + } + object Main { + def main(args: Array[String]): Unit = { + import GetType.* + val e = GetTypeClass + } + } + +package q: + + class C: + def f = + import p.* + GetType.GetTypeClass + def g = + import p.GetType.* + GetTypeClass + class D extends p.Entity[p.Class] diff --git a/tests/warn/i23047.scala b/tests/warn/i23047.scala new file mode 100644 index 000000000000..1922797c3185 --- /dev/null +++ b/tests/warn/i23047.scala @@ -0,0 +1,25 @@ +//> using options -Wunused:imports + +package some.example: + package demo: + + import some.example // no warn because enclosing package example is not available as a simple name in some + + object Main { + + def generic[T](x: Any): T = null.asInstanceOf[T] + + def main(args: Array[String]): Unit = { + generic[example.Util](0) + + import some.example.demo.Main // warn + println(Main) + + import some.example.demo // warn because enclosing package demo is available as a simple name + println(demo.Main) + } + } + +package some.example: + + class Util