@@ -3237,68 +3237,71 @@ class Typer(@constructorOnly nestingLevel: Int = 0) extends Namer
32373237 * parameters of the current class are also defined.
32383238 */
32393239 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+
32403298 if cls.is(Trait ) || ctx.isAfterTyper then body
32413299 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-
32973300 val givenImpls =
32983301 cls.thisType.implicitMembers
32993302 // .showing(i"impl def givens for $cls/$result")
33003303 .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
33023305 // .showing(i"impl def filtered givens for $cls/$result")
33033306 .filter(isGivenValue)
33043307 .map(givenImpl)
0 commit comments