@@ -828,35 +828,63 @@ class Typer extends Namer
828
828
// allow assignments from the primary constructor to class fields
829
829
ctx.owner.name.is(TraitSetterName ) || ctx.owner.isStaticConstructor
830
830
831
- lhsCore.tpe match {
832
- case ref : TermRef =>
833
- val lhsVal = lhsCore.denot.suchThat(! _.is(Method ))
834
- if (canAssign(lhsVal.symbol)) {
835
- // lhsBounds: (T .. Any) as seen from lhs prefix, where T is the type of lhsVal.symbol
836
- // This ensures we do the as-seen-from on T with variance -1. Test case neg/i2928.scala
837
- val lhsBounds =
838
- TypeBounds .lower(lhsVal.symbol.info).asSeenFrom(ref.prefix, lhsVal.symbol.owner)
839
- assignType(cpy.Assign (tree)(lhs1, typed(tree.rhs, lhsBounds.loBound)))
840
- .computeAssignNullable()
831
+ lhsCore match
832
+ case Apply (fn, _) if fn.symbol.isExtensionMethod =>
833
+ def toSetter (fn : Tree ): untpd.Tree = fn match
834
+ case fn @ Ident (name : TermName ) =>
835
+ untpd.cpy.Ident (fn)(name.setterName)
836
+ case fn @ Select (qual, name : TermName ) =>
837
+ untpd.cpy.Select (fn)(untpd.TypedSplice (qual), name.setterName)
838
+ case fn @ TypeApply (fn1, targs) =>
839
+ untpd.cpy.TypeApply (fn)(toSetter(fn1), targs.map(untpd.TypedSplice (_)))
840
+ case fn @ Apply (fn1, args) =>
841
+ val result = untpd.cpy.Apply (fn)(toSetter(fn1), args.map(untpd.TypedSplice (_)))
842
+ fn1 match
843
+ case Apply (_, _) => // current apply is to implicit arguments
844
+ result.setApplyKind(ApplyKind .Using )
845
+ // Note that we cannot copy the apply kind of `fn` since `fn` is a typed
846
+ // tree and applyKinds are not preserved for those.
847
+ case _ => result
848
+ case _ =>
849
+ EmptyTree
850
+
851
+ val setter = toSetter(lhsCore)
852
+ if setter.isEmpty then reassignmentToVal
853
+ else tryEither {
854
+ val assign = untpd.Apply (setter, tree.rhs :: Nil )
855
+ typed(assign, IgnoredProto (pt))
856
+ } {
857
+ (_, _) => reassignmentToVal
841
858
}
842
- else {
843
- val pre = ref.prefix
844
- val setterName = ref.name.setterName
845
- val setter = pre.member(setterName)
846
- lhsCore match {
847
- case lhsCore : RefTree if setter.exists =>
848
- val setterTypeRaw = pre.select(setterName, setter)
849
- val setterType = ensureAccessible(setterTypeRaw, isSuperSelection(lhsCore), tree.sourcePos)
850
- val lhs2 = untpd.rename(lhsCore, setterName).withType(setterType)
851
- typedUnadapted(untpd.Apply (untpd.TypedSplice (lhs2), tree.rhs :: Nil ), WildcardType , locked)
852
- case _ =>
853
- reassignmentToVal
859
+ case _ => lhsCore.tpe match {
860
+ case ref : TermRef =>
861
+ val lhsVal = lhsCore.denot.suchThat(! _.is(Method ))
862
+ if (canAssign(lhsVal.symbol)) {
863
+ // lhsBounds: (T .. Any) as seen from lhs prefix, where T is the type of lhsVal.symbol
864
+ // This ensures we do the as-seen-from on T with variance -1. Test case neg/i2928.scala
865
+ val lhsBounds =
866
+ TypeBounds .lower(lhsVal.symbol.info).asSeenFrom(ref.prefix, lhsVal.symbol.owner)
867
+ assignType(cpy.Assign (tree)(lhs1, typed(tree.rhs, lhsBounds.loBound)))
868
+ .computeAssignNullable()
854
869
}
855
- }
856
- case TryDynamicCallType =>
857
- typedDynamicAssign(tree, pt)
858
- case tpe =>
859
- reassignmentToVal
870
+ else {
871
+ val pre = ref.prefix
872
+ val setterName = ref.name.setterName
873
+ val setter = pre.member(setterName)
874
+ lhsCore match {
875
+ case lhsCore : RefTree if setter.exists =>
876
+ val setterTypeRaw = pre.select(setterName, setter)
877
+ val setterType = ensureAccessible(setterTypeRaw, isSuperSelection(lhsCore), tree.sourcePos)
878
+ val lhs2 = untpd.rename(lhsCore, setterName).withType(setterType)
879
+ typedUnadapted(untpd.Apply (untpd.TypedSplice (lhs2), tree.rhs :: Nil ), WildcardType , locked)
880
+ case _ =>
881
+ reassignmentToVal
882
+ }
883
+ }
884
+ case TryDynamicCallType =>
885
+ typedDynamicAssign(tree, pt)
886
+ case tpe =>
887
+ reassignmentToVal
860
888
}
861
889
}
862
890
0 commit comments