Optional<Boolean> (@Nullable PyType expected, @Nullable PyType actual, @NotNull MatchContext context) { if (Objects.equals(expected, actual)) { return Optional.of(true); } for (PyTypeCheckerExtension extension : PyTypeCheckerExtension.EP_NAME.getExtensionList()) { final Optional<Boolean> result = extension.match(expected, actual, context.context, context.mySubstitutions.typeVars); if (result.isPresent()) { return result; } } if (expected instanceof PyClassType) { Optional<Boolean> match = matchObject((PyClassType)expected, actual); if (match.isPresent()) { return match; } } if (actual instanceof PyTypeVarTupleType typeVarTupleType && context.reversedSubstitutions) { return Optional.of(match(typeVarTupleType, expected, context)); } if (expected instanceof PyVariadicType variadic) { return Optional.of(match(variadic, actual, context)); } if (actual instanceof PyGenericType && context.reversedSubstitutions) { return Optional.of(match((PyGenericType)actual, expected, context)); } if (expected instanceof PyGenericType) { return Optional.of(match((PyGenericType)expected, actual, context)); } if (expected instanceof PySelfType) { return match(context.mySubstitutions.qualifierType, actual, context); } if (actual instanceof PySelfType && context.reversedSubstitutions) { return match(context.mySubstitutions.qualifierType, expected, context); } if (expected instanceof PyParamSpecType) { return Optional.of(match((PyParamSpecType)expected, actual, context)); } if (expected == null || actual == null || isUnknown(actual, context.context)) { return Optional.of(true); } if (actual instanceof PyUnionType) { return Optional.of(match(expected, (PyUnionType)actual, context)); } if (expected instanceof PyUnionType) { return Optional.of(match((PyUnionType)expected, actual, context)); } if (expected instanceof PyClassType && actual instanceof PyClassType) { Optional<Boolean> match = match((PyClassType)expected, (PyClassType)actual, context); if (match.isPresent()) { return match; } } if (actual instanceof PyStructuralType && ((PyStructuralType)actual).isInferredFromUsages()) { return Optional.of(true); } if (expected instanceof PyStructuralType) { return Optional.of(match((PyStructuralType)expected, actual, context.context)); } if (actual instanceof PyStructuralType && expected instanceof PyClassType) { final Set<String> expectedAttributes = ((PyClassType)expected).getMemberNames(true, context.context); return Optional.of(expectedAttributes.containsAll(((PyStructuralType)actual).getAttributeNames())); } if (actual instanceof PyCallableType actualCallable && expected instanceof PyCallableType expectedCallable) { final Optional<Boolean> match = match(expectedCallable, actualCallable, context); if (match.isPresent()) { return match; } } // remove after making PyNoneType inheriting PyClassType if (expected instanceof PyNoneType) { return Optional.of(actual instanceof PyNoneType); } if (expected instanceof PyModuleType) { return Optional.of(actual instanceof PyModuleType && ((PyModuleType)expected).getModule() == ((PyModuleType)actual).getModule()); } if (expected instanceof PyClassType && actual instanceof PyModuleType) { return match(expected, ((PyModuleType)actual).getModuleClassType(), context); } return Optional.of(matchNumericTypes(expected, actual)); }