@@ -3237,68 +3237,71 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
3237
3237
* parameters of the current class are also defined.
3238
3238
*/
3239
3239
def implementDeferredGivens (body : List [Tree ]): List [Tree ] =
3240
+ def failFor (mbr : TermRef , why : String ): false =
3241
+ report.error(
3242
+ em """ Cannot infer the implementation of the deferred ${mbr.symbol.showLocated}
3243
+ |since $why. An implementing given needs to be written explicitly. """ ,
3244
+ cdef.srcPos)
3245
+ false
3246
+ def isGivenValue (mbr : TermRef ) = ! mbr.symbol.is(Method ) || failFor(mbr, " that given is parameterized" )
3247
+
3248
+ def willBeImplementedInParentClass (m : TermRef ) =
3249
+ val superCls = cls.superClass
3250
+ superCls.exists && superCls.asClass.baseClasses.contains(m.symbol.owner)
3251
+
3252
+ def givenImpl (mbr : TermRef ): ValDef =
3253
+ val dcl = mbr.symbol
3254
+ val target = dcl.info.asSeenFrom(cls.thisType, dcl.owner)
3255
+ val constr = cls.primaryConstructor
3256
+ val usingParamAccessors = cls.paramAccessors.filter(_.is(Given ))
3257
+ val paramScope = newScopeWith(usingParamAccessors* )
3258
+ val searchCtx = ctx.outer.fresh.setScope(paramScope)
3259
+
3260
+ // Before losing the reference to ctx.owner
3261
+ // when calling implicitArgTree with searchCtx,
3262
+ // let's store ctx.owner as the fallback "responsibleForImports"
3263
+ // in DependencyRecorder. That way, if we end up recording any dependencies
3264
+ // we use ctx.owner as the "fromClass" rather than emitting a warning
3265
+ // (because ctx.compilationUnit.tpdTree is still EmptyTree during typer).
3266
+ // For example, to record mirror dependencies, see i23049.
3267
+ val depRecorder = ctx.compilationUnit.depRecorder
3268
+ val responsibleForImports = depRecorder._responsibleForImports
3269
+ if responsibleForImports == null then
3270
+ depRecorder._responsibleForImports = ctx.owner
3271
+
3272
+ val rhs = implicitArgTree(target, cdef.span,
3273
+ where = i " inferring the implementation of the deferred ${dcl.showLocated}"
3274
+ )(using searchCtx)
3275
+ val resolvedHere =
3276
+ rhs.tpe match
3277
+ case tp : NamedType => (tp.prefix.typeSymbol eq cls) && tp.name == mbr.name && ! tp.typeSymbol.is(Method )
3278
+ case _ => false
3279
+ if resolvedHere then failFor(mbr, " the result is self-recursive" )
3280
+
3281
+ if responsibleForImports == null then
3282
+ depRecorder._responsibleForImports = null
3283
+
3284
+ val impl = dcl.copy(cls,
3285
+ flags = dcl.flags &~ (HasDefault | Deferred ) | Final | Override ,
3286
+ info = target,
3287
+ coord = rhs.span).entered.asTerm
3288
+
3289
+ def anchorParams = new TreeMap :
3290
+ override def transform (tree : Tree )(using Context ): Tree = tree match
3291
+ case id : Ident if usingParamAccessors.contains(id.symbol) =>
3292
+ cpy.Select (id)(This (cls), id.name)
3293
+ case _ =>
3294
+ super .transform(tree)
3295
+ ValDef (impl, anchorParams.transform(rhs)).withSpan(impl.span.endPos)
3296
+ end givenImpl
3297
+
3240
3298
if cls.is(Trait ) || ctx.isAfterTyper then body
3241
3299
else
3242
- def isGivenValue (mbr : TermRef ) =
3243
- val dcl = mbr.symbol
3244
- if dcl.is(Method ) then
3245
- report.error(
3246
- em """ Cannnot infer the implementation of the deferred ${dcl.showLocated}
3247
- |since that given is parameterized. An implementing given needs to be written explicitly. """ ,
3248
- cdef.srcPos)
3249
- false
3250
- else true
3251
-
3252
- def willBeimplementedInParentClass (m : TermRef ) =
3253
- val superCls = cls.superClass
3254
- superCls.exists && superCls.asClass.baseClasses.contains(m.symbol.owner)
3255
-
3256
- def givenImpl (mbr : TermRef ): ValDef =
3257
- val dcl = mbr.symbol
3258
- val target = dcl.info.asSeenFrom(cls.thisType, dcl.owner)
3259
- val constr = cls.primaryConstructor
3260
- val usingParamAccessors = cls.paramAccessors.filter(_.is(Given ))
3261
- val paramScope = newScopeWith(usingParamAccessors* )
3262
- val searchCtx = ctx.outer.fresh.setScope(paramScope)
3263
-
3264
- // Before losing the reference to ctx.owner
3265
- // when calling implicitArgTree with searchCtx,
3266
- // let's store ctx.owner as the fallback "responsibleForImports"
3267
- // in DependencyRecorder. That way, if we end up recording any dependencies
3268
- // we use ctx.owner as the "fromClass" rather than emitting a warning
3269
- // (because ctx.compilationUnit.tpdTree is still EmptyTree during typer).
3270
- // For example, to record mirror dependencies, see i23049.
3271
- val depRecorder = ctx.compilationUnit.depRecorder
3272
- val responsibleForImports = depRecorder._responsibleForImports
3273
- if responsibleForImports == null then
3274
- depRecorder._responsibleForImports = ctx.owner
3275
-
3276
- val rhs = implicitArgTree(target, cdef.span,
3277
- where = i " inferring the implementation of the deferred ${dcl.showLocated}"
3278
- )(using searchCtx)
3279
-
3280
- if responsibleForImports == null then
3281
- depRecorder._responsibleForImports = null
3282
-
3283
- val impl = dcl.copy(cls,
3284
- flags = dcl.flags &~ (HasDefault | Deferred ) | Final | Override ,
3285
- info = target,
3286
- coord = rhs.span).entered.asTerm
3287
-
3288
- def anchorParams = new TreeMap :
3289
- override def transform (tree : Tree )(using Context ): Tree = tree match
3290
- case id : Ident if usingParamAccessors.contains(id.symbol) =>
3291
- cpy.Select (id)(This (cls), id.name)
3292
- case _ =>
3293
- super .transform(tree)
3294
- ValDef (impl, anchorParams.transform(rhs)).withSpan(impl.span.endPos)
3295
- end givenImpl
3296
-
3297
3300
val givenImpls =
3298
3301
cls.thisType.implicitMembers
3299
3302
// .showing(i"impl def givens for $cls/$result")
3300
3303
.filter(_.symbol.isAllOf(DeferredGivenFlags , butNot = Param ))
3301
- .filter(! willBeimplementedInParentClass (_)) // only implement the given in the topmost class
3304
+ .filter(! willBeImplementedInParentClass (_)) // only implement the given in the topmost class
3302
3305
// .showing(i"impl def filtered givens for $cls/$result")
3303
3306
.filter(isGivenValue)
3304
3307
.map(givenImpl)
0 commit comments