@@ -3183,68 +3183,71 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3183
3183
* parameters of the current class are also defined.
3184
3184
*/
3185
3185
def implementDeferredGivens (body : List [Tree ]): List [Tree ] =
3186
+ def failFor (mbr : TermRef , why : String ): false =
3187
+ report.error(
3188
+ em """ Cannot infer the implementation of the deferred ${mbr.symbol.showLocated}
3189
+ |since $why. An implementing given needs to be written explicitly. """ ,
3190
+ cdef.srcPos)
3191
+ false
3192
+ def isGivenValue (mbr : TermRef ) = ! mbr.symbol.is(Method ) || failFor(mbr, " that given is parameterized" )
3193
+
3194
+ def willBeImplementedInParentClass (m : TermRef ) =
3195
+ val superCls = cls.superClass
3196
+ superCls.exists && superCls.asClass.baseClasses.contains(m.symbol.owner)
3197
+
3198
+ def givenImpl (mbr : TermRef ): ValDef =
3199
+ val dcl = mbr.symbol
3200
+ val target = dcl.info.asSeenFrom(cls.thisType, dcl.owner)
3201
+ val constr = cls.primaryConstructor
3202
+ val usingParamAccessors = cls.paramAccessors.filter(_.is(Given ))
3203
+ val paramScope = newScopeWith(usingParamAccessors* )
3204
+ val searchCtx = ctx.outer.fresh.setScope(paramScope)
3205
+
3206
+ // Before losing the reference to ctx.owner
3207
+ // when calling implicitArgTree with searchCtx,
3208
+ // let's store ctx.owner as the fallback "responsibleForImports"
3209
+ // in DependencyRecorder. That way, if we end up recording any dependencies
3210
+ // we use ctx.owner as the "fromClass" rather than emitting a warning
3211
+ // (because ctx.compilationUnit.tpdTree is still EmptyTree during typer).
3212
+ // For example, to record mirror dependencies, see i23049.
3213
+ val depRecorder = ctx.compilationUnit.depRecorder
3214
+ val responsibleForImports = depRecorder._responsibleForImports
3215
+ if responsibleForImports == null then
3216
+ depRecorder._responsibleForImports = ctx.owner
3217
+
3218
+ val rhs = implicitArgTree(target, cdef.span,
3219
+ where = i " inferring the implementation of the deferred ${dcl.showLocated}"
3220
+ )(using searchCtx)
3221
+ val resolvedHere =
3222
+ rhs.tpe match
3223
+ case tp : NamedType => (tp.prefix.typeSymbol eq cls) && tp.name == mbr.name && ! tp.typeSymbol.is(Method )
3224
+ case _ => false
3225
+ if resolvedHere then failFor(mbr, " the result is self-recursive" )
3226
+
3227
+ if responsibleForImports == null then
3228
+ depRecorder._responsibleForImports = null
3229
+
3230
+ val impl = dcl.copy(cls,
3231
+ flags = dcl.flags &~ (HasDefault | Deferred ) | Final | Override ,
3232
+ info = target,
3233
+ coord = rhs.span).entered.asTerm
3234
+
3235
+ def anchorParams = new TreeMap :
3236
+ override def transform (tree : Tree )(using Context ): Tree = tree match
3237
+ case id : Ident if usingParamAccessors.contains(id.symbol) =>
3238
+ cpy.Select (id)(This (cls), id.name)
3239
+ case _ =>
3240
+ super .transform(tree)
3241
+ ValDef (impl, anchorParams.transform(rhs)).withSpan(impl.span.endPos)
3242
+ end givenImpl
3243
+
3186
3244
if cls.is(Trait ) || ctx.isAfterTyper then body
3187
3245
else
3188
- def isGivenValue (mbr : TermRef ) =
3189
- val dcl = mbr.symbol
3190
- if dcl.is(Method ) then
3191
- report.error(
3192
- em """ Cannnot infer the implementation of the deferred ${dcl.showLocated}
3193
- |since that given is parameterized. An implementing given needs to be written explicitly. """ ,
3194
- cdef.srcPos)
3195
- false
3196
- else true
3197
-
3198
- def willBeimplementedInParentClass (m : TermRef ) =
3199
- val superCls = cls.superClass
3200
- superCls.exists && superCls.asClass.baseClasses.contains(m.symbol.owner)
3201
-
3202
- def givenImpl (mbr : TermRef ): ValDef =
3203
- val dcl = mbr.symbol
3204
- val target = dcl.info.asSeenFrom(cls.thisType, dcl.owner)
3205
- val constr = cls.primaryConstructor
3206
- val usingParamAccessors = cls.paramAccessors.filter(_.is(Given ))
3207
- val paramScope = newScopeWith(usingParamAccessors* )
3208
- val searchCtx = ctx.outer.fresh.setScope(paramScope)
3209
-
3210
- // Before losing the reference to ctx.owner
3211
- // when calling implicitArgTree with searchCtx,
3212
- // let's store ctx.owner as the fallback "responsibleForImports"
3213
- // in DependencyRecorder. That way, if we end up recording any dependencies
3214
- // we use ctx.owner as the "fromClass" rather than emitting a warning
3215
- // (because ctx.compilationUnit.tpdTree is still EmptyTree during typer).
3216
- // For example, to record mirror dependencies, see i23049.
3217
- val depRecorder = ctx.compilationUnit.depRecorder
3218
- val responsibleForImports = depRecorder._responsibleForImports
3219
- if responsibleForImports == null then
3220
- depRecorder._responsibleForImports = ctx.owner
3221
-
3222
- val rhs = implicitArgTree(target, cdef.span,
3223
- where = i " inferring the implementation of the deferred ${dcl.showLocated}"
3224
- )(using searchCtx)
3225
-
3226
- if responsibleForImports == null then
3227
- depRecorder._responsibleForImports = null
3228
-
3229
- val impl = dcl.copy(cls,
3230
- flags = dcl.flags &~ (HasDefault | Deferred ) | Final | Override ,
3231
- info = target,
3232
- coord = rhs.span).entered.asTerm
3233
-
3234
- def anchorParams = new TreeMap :
3235
- override def transform (tree : Tree )(using Context ): Tree = tree match
3236
- case id : Ident if usingParamAccessors.contains(id.symbol) =>
3237
- cpy.Select (id)(This (cls), id.name)
3238
- case _ =>
3239
- super .transform(tree)
3240
- ValDef (impl, anchorParams.transform(rhs)).withSpan(impl.span.endPos)
3241
- end givenImpl
3242
-
3243
3246
val givenImpls =
3244
3247
cls.thisType.implicitMembers
3245
3248
// .showing(i"impl def givens for $cls/$result")
3246
3249
.filter(_.symbol.isAllOf(DeferredGivenFlags , butNot = Param ))
3247
- .filter(! willBeimplementedInParentClass (_)) // only implement the given in the topmost class
3250
+ .filter(! willBeImplementedInParentClass (_)) // only implement the given in the topmost class
3248
3251
// .showing(i"impl def filtered givens for $cls/$result")
3249
3252
.filter(isGivenValue)
3250
3253
.map(givenImpl)
0 commit comments