@@ -20,19 +20,24 @@ import rewrites.Rewrites.patch
20
20
import util .Spans .Span
21
21
22
22
import util .SourcePosition
23
+ import util .Spans .Span
24
+ import rewrites .Rewrites .patch
23
25
import transform .SymUtils ._
26
+ import transform .ValueClasses ._
24
27
import Decorators ._
25
28
import ErrorReporting .{err , errorType }
26
29
import config .Printers .{typr , patmatch }
27
30
import NameKinds .DefaultGetterName
31
+ import NameOps ._
32
+ import SymDenotations .{NoCompleter , NoDenotation }
28
33
import Applications .unapplyArgs
29
34
import transform .patmat .SpaceEngine .isIrrefutableUnapply
30
35
36
+
31
37
import 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
36
41
37
42
object Checking {
38
43
import tpd ._
@@ -716,6 +721,55 @@ trait Checking {
716
721
i " Use of implicit conversion ${conv.showLocated}" , NoSymbol , posd.sourcePos)
717
722
}
718
723
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
+
719
773
/** Issue a feature warning if feature is not enabled */
720
774
def checkFeature (name : TermName ,
721
775
description : => String ,
@@ -985,7 +1039,7 @@ trait Checking {
985
1039
def checkInInlineContext (what : String , posd : Positioned )(implicit ctx : Context ): Unit =
986
1040
if (! ctx.inInlineMethod && ! ctx.isInlineContext) {
987
1041
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 ))
989
1043
val msg =
990
1044
if (inInlineUnapply) " cannot be used in an inline unapply"
991
1045
else " can only be used in an inline method"
@@ -1099,5 +1153,6 @@ trait NoChecking extends ReChecking {
1099
1153
override def checkNoForwardDependencies (vparams : List [ValDef ])(implicit ctx : Context ): Unit = ()
1100
1154
override def checkMembersOK (tp : Type , pos : SourcePosition )(implicit ctx : Context ): Type = tp
1101
1155
override def checkInInlineContext (what : String , posd : Positioned )(implicit ctx : Context ): Unit = ()
1156
+ override def checkValidInfix (tree : untpd.InfixOp , meth : Symbol )(implicit ctx : Context ): Unit = ()
1102
1157
override def checkFeature (name : TermName , description : => String , featureUseSite : Symbol , pos : SourcePosition )(implicit ctx : Context ): Unit = ()
1103
1158
}
0 commit comments