diff --git a/src/Analyser/TypeSpecifier.php b/src/Analyser/TypeSpecifier.php
index c016b2869e..7d378afa71 100644
--- a/src/Analyser/TypeSpecifier.php
+++ b/src/Analyser/TypeSpecifier.php
@@ -331,21 +331,6 @@ public function specifyTypesInCondition(
 				}
 			}
 
-			if (
-				!$context->null()
-				&& $expr->right instanceof FuncCall
-				&& count($expr->right->getArgs()) >= 3
-				&& $expr->right->name instanceof Name
-				&& in_array(strtolower((string) $expr->right->name), ['preg_match'], true)
-				&& IntegerRangeType::fromInterval(0, null)->isSuperTypeOf($leftType)->yes()
-			) {
-				return $this->specifyTypesInCondition(
-					$scope,
-					new Expr\BinaryOp\NotIdentical($expr->right, new ConstFetch(new Name('false'))),
-					$context,
-				)->setRootExpr($expr);
-			}
-
 			if (
 				!$context->null()
 				&& $expr->right instanceof FuncCall
@@ -466,6 +451,24 @@ public function specifyTypesInCondition(
 				}
 			}
 
+			if (
+				!$context->null()
+				&& $expr->right instanceof Expr\CallLike
+			) {
+				if (!$scope instanceof MutatingScope) {
+					throw new ShouldNotHappenException();
+				}
+				$newScope = $scope->filterBySpecifiedTypes($result);
+				$callType = $newScope->getType($expr->right);
+				$newContext = $context->true() ? TypeSpecifierContext::createTrue($callType) : TypeSpecifierContext::createTrue($callType)->negate();
+
+				$result = $result->unionWith($this->specifyTypesInCondition(
+					$scope,
+					$expr->right,
+					$newContext,
+				)->setRootExpr($expr));
+			}
+
 			return $result;
 
 		} elseif ($expr instanceof Node\Expr\BinaryOp\Greater) {
@@ -1173,7 +1176,7 @@ private function specifyTypesForConstantBinaryExpression(
 			return $types->unionWith($this->specifyTypesInCondition(
 				$scope,
 				$exprNode,
-				$context->true() ? TypeSpecifierContext::createTrue() : TypeSpecifierContext::createTrue()->negate(),
+				$context->true() ? TypeSpecifierContext::createTrue($context->getReturnType()) : TypeSpecifierContext::createTrue($context->getReturnType())->negate(),
 			)->setRootExpr($rootExpr));
 		}
 
@@ -1973,7 +1976,7 @@ public function resolveEqual(Expr\BinaryOp\Equal $expr, Scope $scope, TypeSpecif
 				return $this->specifyTypesInCondition(
 					$scope,
 					$exprNode,
-					$context->true() ? TypeSpecifierContext::createFalsey() : TypeSpecifierContext::createFalsey()->negate(),
+					$context->true() ? TypeSpecifierContext::createFalsey($context->getReturnType()) : TypeSpecifierContext::createFalsey($context->getReturnType())->negate(),
 				)->setRootExpr($expr);
 			}
 
diff --git a/src/Analyser/TypeSpecifierContext.php b/src/Analyser/TypeSpecifierContext.php
index fe09aa861c..4044869c11 100644
--- a/src/Analyser/TypeSpecifierContext.php
+++ b/src/Analyser/TypeSpecifierContext.php
@@ -3,6 +3,9 @@
 namespace PHPStan\Analyser;
 
 use PHPStan\ShouldNotHappenException;
+use PHPStan\Type\GeneralizePrecision;
+use PHPStan\Type\Type;
+use PHPStan\Type\TypeCombinator;
 
 /**
  * @api
@@ -21,34 +24,42 @@ final class TypeSpecifierContext
 	/** @var self[] */
 	private static array $registry;
 
-	private function __construct(private ?int $value)
+	private function __construct(
+		private ?int $value,
+		private ?Type $returnType,
+	)
 	{
 	}
 
-	private static function create(?int $value): self
+	private static function create(?int $value, ?Type $returnType = null): self
 	{
-		self::$registry[$value] ??= new self($value);
+		if ($returnType !== null) {
+			// return type bound context is unique for each context and therefore not cacheable
+			return new self($value, $returnType);
+		}
+
+		self::$registry[$value] ??= new self($value, null);
 		return self::$registry[$value];
 	}
 
-	public static function createTrue(): self
+	public static function createTrue(?Type $returnType = null): self
 	{
-		return self::create(self::CONTEXT_TRUE);
+		return self::create(self::CONTEXT_TRUE, $returnType);
 	}
 
-	public static function createTruthy(): self
+	public static function createTruthy(?Type $returnType = null): self
 	{
-		return self::create(self::CONTEXT_TRUTHY);
+		return self::create(self::CONTEXT_TRUTHY, $returnType);
 	}
 
-	public static function createFalse(): self
+	public static function createFalse(?Type $returnType = null): self
 	{
-		return self::create(self::CONTEXT_FALSE);
+		return self::create(self::CONTEXT_FALSE, $returnType);
 	}
 
-	public static function createFalsey(): self
+	public static function createFalsey(?Type $returnType = null): self
 	{
-		return self::create(self::CONTEXT_FALSEY);
+		return self::create(self::CONTEXT_FALSEY, $returnType);
 	}
 
 	public static function createNull(): self
@@ -61,7 +72,14 @@ public function negate(): self
 		if ($this->value === null) {
 			throw new ShouldNotHappenException();
 		}
-		return self::create(~$this->value & self::CONTEXT_BITMASK);
+
+		$negatedReturnType = null;
+		if ($this->returnType !== null) {
+			$baseType = $this->returnType->generalize(GeneralizePrecision::lessSpecific());
+			$negatedReturnType = TypeCombinator::remove($baseType, $this->returnType);
+		}
+
+		return self::create(~$this->value & self::CONTEXT_BITMASK, $negatedReturnType);
 	}
 
 	public function true(): bool
@@ -89,4 +107,9 @@ public function null(): bool
 		return $this->value === null;
 	}
 
+	public function getReturnType(): ?Type
+	{
+		return $this->returnType;
+	}
+
 }
diff --git a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php
index 997cfea752..a232d25a2b 100644
--- a/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php
+++ b/src/Type/Php/InArrayFunctionTypeSpecifyingExtension.php
@@ -147,7 +147,7 @@ public function specifyTypes(FunctionReflection $functionReflection, FuncCall $n
 			$specifiedTypes = $specifiedTypes->unionWith($this->typeSpecifier->create(
 				$node->getArgs()[1]->value,
 				new ArrayType(new MixedType(), $arrayValueType),
-				TypeSpecifierContext::createTrue(),
+				TypeSpecifierContext::createTrue($context->getReturnType()),
 				$scope,
 			));
 		}
diff --git a/tests/PHPStan/Analyser/TypeSpecifierContextReturnTypeExtension.neon b/tests/PHPStan/Analyser/TypeSpecifierContextReturnTypeExtension.neon
new file mode 100644
index 0000000000..6bb9f238df
--- /dev/null
+++ b/tests/PHPStan/Analyser/TypeSpecifierContextReturnTypeExtension.neon
@@ -0,0 +1,5 @@
+services:
+	-
+		class: PHPStan\Tests\TypeSpecifierContextReturnTypeExtension
+		tags:
+			- phpstan.typeSpecifier.methodTypeSpecifyingExtension
diff --git a/tests/PHPStan/Analyser/TypeSpecifierContextReturnTypeTest.php b/tests/PHPStan/Analyser/TypeSpecifierContextReturnTypeTest.php
new file mode 100644
index 0000000000..cf404559b5
--- /dev/null
+++ b/tests/PHPStan/Analyser/TypeSpecifierContextReturnTypeTest.php
@@ -0,0 +1,35 @@
+<?php declare(strict_types = 1);
+
+namespace PHPStan\Analyser;
+
+use PHPStan\Testing\TypeInferenceTestCase;
+
+class TypeSpecifierContextReturnTypeTest extends TypeInferenceTestCase
+{
+
+	public function dataContextReturnType(): iterable
+	{
+		yield from $this->gatherAssertTypes(__DIR__ . '/data/type-specifier-context-return-type.php');
+	}
+
+	/**
+	 * @dataProvider dataContextReturnType
+	 * @param mixed ...$args
+	 */
+	public function testContextReturnType(
+		string $assertType,
+		string $file,
+		...$args,
+	): void
+	{
+		$this->assertFileAsserts($assertType, $file, ...$args);
+	}
+
+	public static function getAdditionalConfigFiles(): array
+	{
+		return [
+			__DIR__ . '/TypeSpecifierContextReturnTypeExtension.neon',
+		];
+	}
+
+}
diff --git a/tests/PHPStan/Analyser/data/TypeSpecifierContextReturnTypeExtension.php b/tests/PHPStan/Analyser/data/TypeSpecifierContextReturnTypeExtension.php
new file mode 100644
index 0000000000..906bd0f304
--- /dev/null
+++ b/tests/PHPStan/Analyser/data/TypeSpecifierContextReturnTypeExtension.php
@@ -0,0 +1,59 @@
+<?php declare(strict_types = 1);
+
+namespace PHPStan\Tests;
+
+use PhpParser\Node\Expr\MethodCall;
+use PHPStan\Analyser\Scope;
+use PHPStan\Analyser\SpecifiedTypes;
+use PHPStan\Analyser\TypeSpecifier;
+use PHPStan\Analyser\TypeSpecifierAwareExtension;
+use PHPStan\Analyser\TypeSpecifierContext;
+use PHPStan\Reflection\MethodReflection;
+use PHPStan\Type\MethodTypeSpecifyingExtension;
+use TypeSpecifierContextReturnTypeTest\ContextReturnType;
+use function str_starts_with;
+
+class TypeSpecifierContextReturnTypeExtension implements MethodTypeSpecifyingExtension, TypeSpecifierAwareExtension
+{
+
+	private TypeSpecifier $typeSpecifier;
+
+	public function setTypeSpecifier(TypeSpecifier $typeSpecifier): void
+	{
+		$this->typeSpecifier = $typeSpecifier;
+	}
+
+	public function getClass(): string
+	{
+		return ContextReturnType::class;
+	}
+
+	public function isMethodSupported(
+		MethodReflection $methodReflection,
+		MethodCall $node,
+		TypeSpecifierContext $context,
+	): bool
+	{
+		return str_starts_with($methodReflection->getName(), 'returns');
+	}
+
+	public function specifyTypes(
+		MethodReflection $methodReflection,
+		MethodCall $node,
+		Scope $scope,
+		TypeSpecifierContext $context,
+	): SpecifiedTypes
+	{
+        if ($context->null()) {
+            return new SpecifiedTypes();
+        }
+
+		return $this->typeSpecifier->create(
+			$node->getArgs()[0]->value,
+			$context->getReturnType(),
+			$context,
+			$scope,
+		);
+	}
+
+}
diff --git a/tests/PHPStan/Analyser/data/type-specifier-context-return-type.php b/tests/PHPStan/Analyser/data/type-specifier-context-return-type.php
new file mode 100644
index 0000000000..2303d938f6
--- /dev/null
+++ b/tests/PHPStan/Analyser/data/type-specifier-context-return-type.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace TypeSpecifierContextReturnTypeTest;
+
+use function PHPStan\Testing\assertType;
+
+class ContextReturnType {
+	public function returnsInt(int $specifiedContextReturnType): int {}
+
+	public function doFooLeft(int $i) {
+		assertType('int', $i);
+		if ($this->returnsInt($i) > 0) {
+			assertType('int<1, max>', $i);
+		} else {
+			assertType('int<min, 0>', $i);
+		}
+		assertType('int', $i);
+	}
+
+	public function doFooRight(int $i) {
+		assertType('int', $i);
+		if (0 < $this->returnsInt($i)) {
+			assertType('int<1, max>', $i);
+		} else {
+			assertType('int<min, 0>', $i);
+		}
+		assertType('int', $i);
+	}
+}