@@ -512,6 +512,80 @@ object Checking {
512512 }
513513 }
514514
515+ def checkScala2Implicit (sym : Symbol )(using Context ): Unit =
516+ def migration (msg : Message ) =
517+ report.errorOrMigrationWarning(msg, sym.srcPos, MigrationVersion .Scala2Implicits )
518+ def info = sym match
519+ case sym : ClassSymbol => sym.primaryConstructor.info
520+ case _ => sym.info
521+ def paramName = info.firstParamNames match
522+ case pname :: _ => pname.show
523+ case _ => " x"
524+ def paramTypeStr = info.firstParamTypes match
525+ case pinfo :: _ => pinfo.show
526+ case _ => " T"
527+ def toFunctionStr (info : Type ): String = info match
528+ case ExprType (resType) =>
529+ i " () => $resType"
530+ case info : MethodType =>
531+ i " ( ${ctx.printer.paramsText(info).mkString()}) => ${toFunctionStr(info.resType)}"
532+ case info : PolyType =>
533+ i " [ ${ctx.printer.paramsText(info).mkString()}] => ${toFunctionStr(info.resType)}"
534+ case _ =>
535+ info.show
536+
537+ if sym.isClass then
538+ migration(
539+ em """ `implicit` classes are no longer supported. They can usually be replaced
540+ |by extension methods. Example:
541+ |
542+ | extension ( $paramName: $paramTypeStr)
543+ | // class methods go here, replace `this` by ` $paramName`
544+ |
545+ |Alternatively, convert to a regular class and define
546+ |a given `Conversion` instance into that class. Example:
547+ |
548+ | class ${sym.name} ...
549+ | given Conversion[ $paramTypeStr, ${sym.name}] = ${sym.name}( $paramName)
550+ |
551+ | """ )
552+ else if sym.isOldStyleImplicitConversion(directOnly = true ) then
553+ migration(
554+ em """ `implicit` conversion methods are no longer supported. They can usually be
555+ |replaced by given instances of class `Conversion`. Example:
556+ |
557+ | given Conversion[ $paramTypeStr, ${sym.info.finalResultType}] = $paramName => ...
558+ |
559+ | """ )
560+ else if sym.is(Method ) then
561+ if ! sym.isOldStyleImplicitConversion(forImplicitClassOnly = true ) then
562+ migration(
563+ em """ `implicit` defs are no longer supported, use a `given` clause instead. Example:
564+ |
565+ | given ${sym.name}: ${toFunctionStr(sym.info)} = ...
566+ |
567+ | """ )
568+ else if sym.isTerm && ! sym.isOneOf(TermParamOrAccessor ) then
569+ def note =
570+ if sym.is(Lazy ) then " "
571+ else
572+ i """
573+ |
574+ |Note: given clauses are evaluated lazily unless the right hand side is
575+ |a simple reference. If eager evaluation of the value's right hand side
576+ |is important, you can define a regular val and a given instance like this:
577+ |
578+ | val ${sym.name} = ...
579+ | given ${sym.info} = ${sym.name}"""
580+
581+ migration(
582+ em """ `implicit` vals are no longer supported, use a `given` clause instead. Example:
583+ |
584+ | given ${sym.name}: ${sym.info} = ... $note
585+ |
586+ | """ )
587+ end checkScala2Implicit
588+
515589 /** Check that symbol's definition is well-formed. */
516590 def checkWellFormed (sym : Symbol )(using Context ): Unit = {
517591 def fail (msg : Message ) = report.error(msg, sym.srcPos)
@@ -537,11 +611,11 @@ object Checking {
537611 fail(ParamsNoInline (sym.owner))
538612 if sym.isInlineMethod && ! sym.is(Deferred ) && sym.allOverriddenSymbols.nonEmpty then
539613 checkInlineOverrideParameters(sym)
540- if ( sym.is(Implicit )) {
614+ if sym.is(Implicit ) then
541615 assert(! sym.owner.is(Package ), s " top-level implicit $sym should be wrapped by a package after typer " )
542616 if sym.isType && (! sym.isClass || sym.is(Trait )) then
543617 fail(TypesAndTraitsCantBeImplicit ())
544- }
618+ else checkScala2Implicit(sym)
545619 if sym.is(Transparent ) then
546620 if sym.isType then
547621 if ! sym.isExtensibleClass then fail(em " `transparent` can only be used for extensible classes and traits " )
0 commit comments