summaryrefslogtreecommitdiff
path: root/src/compiler/scala/tools/nsc/typechecker
diff options
context:
space:
mode:
Diffstat (limited to 'src/compiler/scala/tools/nsc/typechecker')
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Namers.scala11
-rw-r--r--src/compiler/scala/tools/nsc/typechecker/Typers.scala2
2 files changed, 8 insertions, 5 deletions
diff --git a/src/compiler/scala/tools/nsc/typechecker/Namers.scala b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
index 78e8c8c073..27a586e543 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Namers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Namers.scala
@@ -902,9 +902,10 @@ trait Namers extends MethodSynthesis {
// Annotations on ValDefs can be targeted towards the following: field, getter, setter, beanGetter, beanSetter, param.
// The defaults are:
// - (`val`-, `var`- or plain) constructor parameter annotations end up on the parameter, not on any other entity.
- // - val/var member annotations solely end up on the underlying field, except in traits (@since 2.12),
+ // - val/var member annotations solely end up on the underlying field, except in traits and for all lazy vals (@since 2.12),
// where there is no field, and the getter thus holds annotations targeting both getter & field.
- // As soon as there is a field/getter (in subclasses mixing in the trait), we triage the annotations.
+ // As soon as there is a field/getter (in subclasses mixing in the trait, or after expanding the lazy val during the fields phase),
+ // we triage the annotations.
//
// TODO: these defaults can be surprising for annotations not meant for accessors/fields -- should we revisit?
// (In order to have `@foo val X` result in the X getter being annotated with `@foo`, foo needs to be meta-annotated with @getter)
@@ -918,15 +919,17 @@ trait Namers extends MethodSynthesis {
BeanPropertyAnnotationLimitationError(tree)
}
+ val canTriageAnnotations = isSetter || !fields.getterTreeAnnotationsTargetFieldAndGetter(owner, mods)
+
def filterAccessorAnnotations: AnnotationInfo => Boolean =
- if (isSetter || !owner.isTrait)
+ if (canTriageAnnotations)
annotationFilter(if (isSetter) SetterTargetClass else GetterTargetClass, defaultRetention = false)
else (ann =>
annotationFilter(FieldTargetClass, defaultRetention = true)(ann) ||
annotationFilter(GetterTargetClass, defaultRetention = true)(ann))
def filterBeanAccessorAnnotations: AnnotationInfo => Boolean =
- if (isSetter || !owner.isTrait)
+ if (canTriageAnnotations)
annotationFilter(if (isSetter) BeanSetterTargetClass else BeanGetterTargetClass, defaultRetention = false)
else (ann =>
annotationFilter(FieldTargetClass, defaultRetention = true)(ann) ||
diff --git a/src/compiler/scala/tools/nsc/typechecker/Typers.scala b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
index 78533bdfc5..82733c1643 100644
--- a/src/compiler/scala/tools/nsc/typechecker/Typers.scala
+++ b/src/compiler/scala/tools/nsc/typechecker/Typers.scala
@@ -2034,7 +2034,7 @@ trait Typers extends Adaptations with Tags with TypersTracking with PatternTyper
// allow trait accessors: it's the only vehicle we have to hang on to annotations that must be passed down to
// the field that's mixed into a subclass
- if (sym.hasAnnotation(definitions.VolatileAttr) && !((sym hasFlag MUTABLE) || (sym hasFlag ACCESSOR) && sym.owner.isTrait))
+ if (sym.hasAnnotation(definitions.VolatileAttr) && !((sym hasFlag MUTABLE | LAZY) || (sym hasFlag ACCESSOR) && sym.owner.isTrait))
VolatileValueError(vdef)
val rhs1 =