PY-78236 Migrate PyDocStringTypeProvider#setTypeVarScopeOwners to PyCloningTypeVisitor

It allowed to get rid of PyGenericType.setScopeOwner hack, modifying the type inplace.

GitOrigin-RevId: dd9389ae496a7e1afa3bc7101d907fcc3d170d5e
This commit is contained in:
Mikhail Golubev
2025-02-14 18:53:22 +00:00
committed by intellij-monorepo-bot
parent 80f2df2d3e
commit c8002968cc
2 changed files with 20 additions and 30 deletions
@@ -11,7 +11,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Set;
import java.util.function.Function;
/**
* @author Mikhail Golubev
@@ -69,7 +68,17 @@ public final class PyDocStringTypeProvider extends PyTypeProviderBase {
if (type != null) {
type.assertValid("from docstring");
}
setTypeVarScopeOwners(type, callable, context);
if (callable instanceof PyFunction pyFunction) {
return Ref.create(PyCloningTypeVisitor.clone(type, new PyCloningTypeVisitor(context) {
@Override
public PyType visitPyTypeVarType(@NotNull PyTypeVarType typeVarType) {
if (typeVarType instanceof PyTypeVarTypeImpl impl) {
return impl.withScopeOwner(findScopeOwner(typeVarType, pyFunction, context));
}
return typeVarType;
}
}));
}
return Ref.create(type);
}
@@ -89,31 +98,21 @@ public final class PyDocStringTypeProvider extends PyTypeProviderBase {
return null;
}
// A hack to update scope owners of type parameters parsed out of docstrings
private void setTypeVarScopeOwners(@Nullable PyType type, @NotNull PyCallable callable, @NotNull TypeEvalContext context) {
if (!(callable instanceof PyFunction pyFunction)) return;
PyTypeChecker.Generics typeParameters = PyTypeChecker.collectGenerics(type, context);
if (typeParameters.isEmpty()) return;
PyClass pyClass = pyFunction.getContainingClass();
Function<PyTypeVarType, PyQualifiedNameOwner> findScopeOwner = typeVar -> pyFunction;
if (PyUtil.isInitOrNewMethod(callable)) {
findScopeOwner = typeVar -> pyClass;
private PyQualifiedNameOwner findScopeOwner(@NotNull PyTypeVarType typeVar,
@NotNull PyFunction function,
@NotNull TypeEvalContext context) {
PyClass pyClass = function.getContainingClass();
if (PyUtil.isInitOrNewMethod(function)) {
return pyClass;
}
else if (pyClass != null) {
PyType classGenericType = getGenericType(pyClass, context);
if (classGenericType != null) {
PyTypeChecker.Generics classTypeParameters = PyTypeChecker.collectGenerics(classGenericType, context);
Set<String> classTypeVarNames = ContainerUtil.map2Set(classTypeParameters.getTypeVars(), PyTypeVarType::getName);
findScopeOwner = typeVar -> classTypeVarNames.contains(typeVar.getName()) ? pyClass : pyFunction;
}
}
for (PyTypeParameterType typeParam : typeParameters.getAllTypeParameters()) {
if (typeParam instanceof PyTypeVarTypeImpl typeVar) {
typeVar.setScopeOwner(findScopeOwner.apply(typeVar));
return classTypeVarNames.contains(typeVar.getName()) ? pyClass : function;
}
}
return function;
}
}
@@ -11,7 +11,6 @@ import com.jetbrains.python.psi.PyQualifiedNameOwner;
import com.jetbrains.python.psi.PyTargetExpression;
import com.jetbrains.python.psi.resolve.PyResolveContext;
import com.jetbrains.python.psi.resolve.RatedResolveResult;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -30,7 +29,7 @@ public class PyGenericType implements PyTypeVarType {
private final @Nullable Ref<PyType> myDefaultType;
private final boolean myIsDefinition;
private final @Nullable PyQualifiedNameOwner myDeclarationElement;
private @Nullable PyQualifiedNameOwner myScopeOwner;
private final @Nullable PyQualifiedNameOwner myScopeOwner;
public PyGenericType(@NotNull String name,
@NotNull List<@Nullable PyType> constraints,
@@ -166,14 +165,6 @@ public class PyGenericType implements PyTypeVarType {
return new PyTypeVarTypeImpl(getName(), getConstraints(), getBound(), getDefaultType(), isDefinition(), declarationElement, getScopeOwner());
}
@ApiStatus.Internal
public void setScopeOwner(@NotNull PyQualifiedNameOwner scopeOwner) {
if (myScopeOwner != null && myScopeOwner != scopeOwner) {
throw new IllegalStateException("Cannot override the existing scope owner");
}
myScopeOwner = scopeOwner;
}
@Override
public @NotNull PyGenericType toInstance() {
return myIsDefinition ? new PyTypeVarTypeImpl(myName, myConstraints, myBound, myDefaultType, false, myDeclarationElement, myScopeOwner) : this;