@@ -3183,68 +3183,71 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
31833183 * parameters of the current class are also defined.
31843184 */
31853185 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+
31863244 if cls.is(Trait ) || ctx.isAfterTyper then body
31873245 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-
32433246 val givenImpls =
32443247 cls.thisType.implicitMembers
32453248 // .showing(i"impl def givens for $cls/$result")
32463249 .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
32483251 // .showing(i"impl def filtered givens for $cls/$result")
32493252 .filter(isGivenValue)
32503253 .map(givenImpl)
0 commit comments