@@ -20,19 +20,24 @@ import rewrites.Rewrites.patch
2020import util .Spans .Span
2121
2222import util .SourcePosition
23+ import util .Spans .Span
24+ import rewrites .Rewrites .patch
2325import transform .SymUtils ._
26+ import transform .ValueClasses ._
2427import Decorators ._
2528import ErrorReporting .{err , errorType }
2629import config .Printers .{typr , patmatch }
2730import NameKinds .DefaultGetterName
31+ import NameOps ._
32+ import SymDenotations .{NoCompleter , NoDenotation }
2833import Applications .unapplyArgs
2934import transform .patmat .SpaceEngine .isIrrefutableUnapply
3035
36+
3137import collection .mutable
32- import SymDenotations .{NoCompleter , NoDenotation }
33- import dotty .tools .dotc .reporting .diagnostic .Message
34- import dotty .tools .dotc .reporting .diagnostic .messages ._
35- import dotty .tools .dotc .transform .ValueClasses ._
38+ import reporting .diagnostic .Message
39+ import reporting .diagnostic .messages ._
40+ import scala .tasty .util .Chars .isOperatorPart
3641
3742object Checking {
3843 import tpd ._
@@ -716,6 +721,55 @@ trait Checking {
716721 i " Use of implicit conversion ${conv.showLocated}" , NoSymbol , posd.sourcePos)
717722 }
718723
724+ private def infixOKSinceFollowedBy (tree : untpd.Tree ): Boolean = tree match {
725+ case _ : untpd.Block | _ : untpd.Match => true
726+ case _ => false
727+ }
728+
729+ /** Check that `tree` is a valid infix operation. That is, if the
730+ * operator is alphanumeric, it must be declared `@infix`.
731+ */
732+ def checkValidInfix (tree : untpd.InfixOp , meth : Symbol )(implicit ctx : Context ): Unit = {
733+
734+ def isInfix (sym : Symbol ): Boolean =
735+ sym.hasAnnotation(defn.InfixAnnot ) ||
736+ defn.isInfix(sym) ||
737+ sym.name.isUnapplyName &&
738+ sym.owner.is(Module ) && sym.owner.linkedClass.is(Case ) &&
739+ isInfix(sym.owner.linkedClass)
740+
741+ tree.op match {
742+ case _ : untpd.BackquotedIdent =>
743+ ()
744+ case Ident (name : Name ) =>
745+ name.toTermName match {
746+ case name : SimpleName
747+ if ! name.exists(isOperatorPart) &&
748+ ! isInfix(meth) &&
749+ ! meth.maybeOwner.is(Scala2x ) &&
750+ ! infixOKSinceFollowedBy(tree.right) &&
751+ ctx.settings.strict.value =>
752+ val (kind, alternative) =
753+ if (ctx.mode.is(Mode .Type ))
754+ (" type" , (n : Name ) => s " prefix syntax $n[...] " )
755+ else if (ctx.mode.is(Mode .Pattern ))
756+ (" extractor" , (n : Name ) => s " prefix syntax $n(...) " )
757+ else
758+ (" method" , (n : Name ) => s " method syntax . $n(...) " )
759+ ctx.deprecationWarning(
760+ i """ Alphanumeric $kind $name is not declared @infix; it should not be used as infix operator.
761+ |The operation can be rewritten automatically to ` $name` under -deprecation -rewrite.
762+ |Or rewrite to ${alternative(name)} manually. """ ,
763+ tree.op.sourcePos)
764+ if (ctx.settings.deprecation.value) {
765+ patch(Span (tree.op.span.start, tree.op.span.start), " `" )
766+ patch(Span (tree.op.span.end, tree.op.span.end), " `" )
767+ }
768+ case _ =>
769+ }
770+ }
771+ }
772+
719773 /** Issue a feature warning if feature is not enabled */
720774 def checkFeature (name : TermName ,
721775 description : => String ,
@@ -985,7 +1039,7 @@ trait Checking {
9851039 def checkInInlineContext (what : String , posd : Positioned )(implicit ctx : Context ): Unit =
9861040 if (! ctx.inInlineMethod && ! ctx.isInlineContext) {
9871041 val inInlineUnapply = ctx.owner.ownersIterator.exists(owner =>
988- owner.name == nme.unapply && owner.is(Inline ) && owner.is(Method ))
1042+ owner.name.isUnapplyName && owner.is(Inline ) && owner.is(Method ))
9891043 val msg =
9901044 if (inInlineUnapply) " cannot be used in an inline unapply"
9911045 else " can only be used in an inline method"
@@ -1099,5 +1153,6 @@ trait NoChecking extends ReChecking {
10991153 override def checkNoForwardDependencies (vparams : List [ValDef ])(implicit ctx : Context ): Unit = ()
11001154 override def checkMembersOK (tp : Type , pos : SourcePosition )(implicit ctx : Context ): Type = tp
11011155 override def checkInInlineContext (what : String , posd : Positioned )(implicit ctx : Context ): Unit = ()
1156+ override def checkValidInfix (tree : untpd.InfixOp , meth : Symbol )(implicit ctx : Context ): Unit = ()
11021157 override def checkFeature (name : TermName , description : => String , featureUseSite : Symbol , pos : SourcePosition )(implicit ctx : Context ): Unit = ()
11031158}
0 commit comments